clang 24.0.0git
CIRGenBuiltinAArch64.cpp
Go to the documentation of this file.
1//===---- CIRGenBuiltinAArch64.cpp - Emit CIR for AArch64 builtins --------===//
2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3// See https://llvm.org/LICENSE.txt for license information.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7//
8// This contains code to emit ARM64 Builtin calls as CIR or a function call
9// to be later resolved.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenBuilder.h"
14#include "CIRGenFunction.h"
19
20// TODO(cir): once all builtins are covered, decide whether we still
21// need to use LLVM intrinsics or if there's a better approach to follow. Right
22// now the intrinsics are reused to make it convenient to encode all thousands
23// of them and passing down to LLVM lowering.
24#include "llvm/IR/Intrinsics.h"
25#include "llvm/IR/IntrinsicsAArch64.h"
26
27#include "mlir/IR/BuiltinTypes.h"
28#include "mlir/IR/Value.h"
31
32using namespace clang;
33using namespace clang::CIRGen;
34using namespace llvm;
35using namespace clang::aarch64;
36
37// Generate vscale * scalingFactor
38static mlir::Value genVscaleTimesFactor(mlir::Location loc,
39 CIRGenBuilderTy builder,
40 mlir::Type cirTy,
41 int32_t scalingFactor) {
42 mlir::Value vscale = builder.emitIntrinsicCallOp(loc, "vscale", cirTy);
43 return builder.createNUWAMul(loc, vscale,
44 builder.getUInt64(scalingFactor, loc));
45}
46
47#define SVEMAP1(NameBase, LLVMIntrinsic, TypeModifier) \
48 {SVE::BI__builtin_sve_##NameBase, Intrinsic::LLVMIntrinsic, TypeModifier}
49
50#define SVEMAP2(NameBase, TypeModifier) \
51 {SVE::BI__builtin_sve_##NameBase, 0, TypeModifier}
53#define GET_SVE_LLVM_INTRINSIC_MAP
54#include "clang/Basic/arm_sve_builtin_cg.inc"
55#undef GET_SVE_LLVM_INTRINSIC_MAP
56};
57
61
62// Check if Builtin `builtinId` is present in `intrinsicMap`. If yes, returns
63// the corresponding info struct.
64template <typename IntrinsicInfo>
65static const IntrinsicInfo *
67 unsigned builtinID, bool &mapProvenSorted) {
68
69#ifndef NDEBUG
70 if (!mapProvenSorted) {
71 assert(llvm::is_sorted(intrinsicMap));
72 mapProvenSorted = true;
73 }
74#endif
75
76 const IntrinsicInfo *info = llvm::lower_bound(intrinsicMap, builtinID);
77
78 if (info != intrinsicMap.end() && info->BuiltinID == builtinID)
79 return info;
80
81 return nullptr;
82}
83
84//===----------------------------------------------------------------------===//
85// Generic helpers
86//===----------------------------------------------------------------------===//
87static llvm::StringRef getLLVMIntrNameNoPrefix(llvm::Intrinsic::ID intrID) {
88 llvm::StringRef llvmIntrName = llvm::Intrinsic::getBaseName(intrID);
89 assert(llvmIntrName.starts_with("llvm.") && "Not an LLVM intrinsic!");
90 return llvmIntrName.drop_front(/*strlen("llvm.")=*/5);
91}
92
93//===----------------------------------------------------------------------===//
94// NEON helpers
95//===----------------------------------------------------------------------===//
96/// Return true if BuiltinID is an overloaded Neon intrinsic with an extra
97/// argument that specifies the vector type. The additional argument is meant
98/// for Sema checking (see `CheckNeonBuiltinFunctionCall`) and this function
99/// should be kept consistent with the logic in Sema.
100/// TODO: Make this return false for SISD builtins.
101/// TODO(cir): Share this with ARM.cpp
102static bool hasExtraNeonArgument(unsigned builtinID) {
103 // Required by the headers included below, but not in this particular
104 // function.
105 [[maybe_unused]] int PtrArgNum = -1;
106 [[maybe_unused]] bool HasConstPtr = false;
107
108 // The mask encodes the type. We don't care about the actual value. Instead,
109 // we just check whether its been set.
110 uint64_t mask = 0;
111 switch (builtinID) {
112#define GET_NEON_OVERLOAD_CHECK
113#include "clang/Basic/arm_fp16.inc"
114#include "clang/Basic/arm_neon.inc"
115#undef GET_NEON_OVERLOAD_CHECK
116 // Non-neon builtins for controling VFP that take extra argument for
117 // discriminating the type.
118 case ARM::BI__builtin_arm_vcvtr_f:
119 case ARM::BI__builtin_arm_vcvtr_d:
120 mask = 1;
121 }
122 switch (builtinID) {
123 default:
124 break;
125 }
126
127 return mask != 0;
128}
129
130static cir::VectorType getFloatNeonType(CIRGenFunction &cgf,
131 NeonTypeFlags intTypeFlags) {
132 int isQuad = intTypeFlags.isQuad();
133 switch (intTypeFlags.getEltType()) {
135 return cir::VectorType::get(cgf.fP16Ty, (4 << isQuad));
137 return cir::VectorType::get(cgf.floatTy, (2 << isQuad));
139 return cir::VectorType::get(cgf.doubleTy, (1 << isQuad));
140 default:
141 llvm_unreachable("Type can't be converted to floating-point!");
142 }
143}
144
145static int64_t getIntValueFromConstOp(mlir::Value val) {
146 return val.getDefiningOp<cir::ConstantOp>().getIntValue().getSExtValue();
147}
148
149/// Build a constant shift amount vector of `vecTy` to shift a vector
150/// Here `shiftVal` is a constant integer that will be broadcast into a
151/// a const vector of `vecTy` which is the return value of this function
152/// If `neg` is true, the shift amount is negated before splatting (used
153/// when encoding a right shift as a left shift by a negative amount for
154/// intrinsics like aarch64.neon.{s,u}rshl).
155static mlir::Value emitNeonShiftVector(CIRGenBuilderTy &builder,
156 mlir::Value shiftVal,
157 cir::VectorType vecTy,
158 mlir::Location loc, bool neg) {
159 if (neg) {
160 int64_t shiftAmt = -getIntValueFromConstOp(shiftVal);
161 shiftVal = builder.getConstantInt(loc, vecTy.getElementType(), shiftAmt);
162 }
163 mlir::Type eltTy = vecTy.getElementType();
164 if (shiftVal.getType() != eltTy) {
165 shiftVal = builder.createIntCast(shiftVal, eltTy);
166 }
167 return cir::VecSplatOp::create(builder, loc, vecTy, shiftVal);
168}
169
170// TODO(cir): Remove `cgm` from the list of arguments once all NYI(s) are gone.
171template <typename Operation>
172static mlir::Value
176 std::optional<llvm::StringRef> intrinsicName,
177 mlir::Type funcResTy, mlir::Location loc,
178 bool isConstrainedFPIntrinsic = false, unsigned shift = 0,
179 bool rightshift = false) {
180 // TODO(cir): Consider removing the following unreachable when we have
181 // emitConstrainedFPCall feature implemented
183 if (isConstrainedFPIntrinsic)
184 cgm.errorNYI(loc, std::string("constrained FP intrinsic"));
185
186 for (unsigned j = 0; j < argTypes.size(); ++j) {
187 if (isConstrainedFPIntrinsic) {
189 }
190 if (shift > 0 && shift == j) {
191 args[j] = emitNeonShiftVector(builder, args[j],
192 mlir::cast<cir::VectorType>(argTypes[j]),
193 loc, rightshift);
194 } else {
195 args[j] = builder.createBitcast(args[j], argTypes[j]);
196 }
197 }
198 if (isConstrainedFPIntrinsic) {
200 return nullptr;
201 }
202 if constexpr (std::is_same_v<Operation, cir::LLVMIntrinsicCallOp>) {
203 return Operation::create(builder, loc,
204 builder.getStringAttr(intrinsicName.value()),
205 funcResTy, args)
206 .getResult();
207 } else {
208 return Operation::create(
209 builder, loc, mlir::TypeRange{funcResTy}, args,
210 cir::getDefaultProperties<Operation>(builder.getContext()))
211 .getResult();
212 }
213}
214
215// TODO(cir): Remove `cgm` from the list of arguments once all NYI(s) are gone.
216static mlir::Value emitNeonCall(CIRGenModule &cgm, CIRGenBuilderTy &builder,
219 llvm::StringRef intrinsicName,
220 mlir::Type funcResTy, mlir::Location loc,
221 bool isConstrainedFPIntrinsic = false,
222 unsigned shift = 0, bool rightshift = false) {
224 cgm, builder, std::move(argTypes), args, intrinsicName, funcResTy, loc,
225 isConstrainedFPIntrinsic, shift, rightshift);
226}
227
228// Computes the input vector type for a NEON pairwise widening operation (e.g.
229// vpaddl/vpadal). Given a result vector type, it derives the corresponding
230// input type by halving the element bit width and doubling the number of lanes,
231// while setting the signedness based on usgn.
232static cir::VectorType getNeonPairwiseWidenInputType(cir::VectorType resType,
233 bool usgn) {
234 mlir::Type elemTy = resType.getElementType();
235 uint64_t resLanes = resType.getSize();
236 auto intTy = mlir::dyn_cast<cir::IntType>(elemTy);
237 assert(intTy && "vpaddl result type must be an integer vector");
238
239 unsigned resWidth = intTy.getWidth();
240 assert((resWidth == 16 || resWidth == 32 || resWidth == 64) &&
241 "unexpected vpaddl result element width");
242
243 unsigned argWidth = resWidth / 2;
244 unsigned argLanes = resLanes * 2;
245 cir::VectorType result = cir::VectorType::get(
246 cir::IntType::get(resType.getContext(), argWidth, /* is_signed */ !usgn),
247 argLanes);
248 return result;
249}
250
251// Derive the LLVM intrinsic's per-operand argument types and its result
252// type for use when emitting the intrinsic call.
253//
254// `modifier` is the TypeModifier bitmask from `ARMNeonVectorIntrinsicInfo`
255// (callers pass `info.TypeModifier`; see AArch64CodeGenUtils.h). It encodes
256// how the intrinsic's argument and return types relate to the builtin's
257// scalar types. For SISD builtins the key flags are:
258// - VectorizeArgTypes: wrap each arg type into a fixed-width vector
259// - Use64BitVectors / Use128BitVectors: choose the vector width
260// (when neither is set the vector has 1 element)
261// - AddRetType / VectorizeRetType: analogous flags for the return type
262//
263// ARM.cpp lets LLVM resolve the intrinsic's signature (via
264// `CGM.getIntrinsic`) and then walks the resolved Function* formal
265// parameter types. CIR has no LLVMContext here, so we derive the same
266// argument/result types directly from the Clang operand types.
267static std::pair<mlir::Type, llvm::SmallVector<mlir::Type>>
269 mlir::Type arg0Ty, mlir::Type resultTy,
271 unsigned iceArguments) {
272 int vectorSize = 0;
273 if (modifier & Use64BitVectors)
274 vectorSize = 64;
275 else if (modifier & Use128BitVectors)
276 vectorSize = 128;
277
278 auto wrapAsVector = [&](mlir::Type ty) -> cir::VectorType {
279 unsigned bits = cgf.cgm.getDataLayout().getTypeSizeInBits(ty);
280 unsigned elts = vectorSize ? vectorSize / bits : 1;
281 return cir::VectorType::get(ty, elts);
282 };
283
284 // Determine the vectorized data type.
285 cir::VectorType vecArgTy;
286 if (modifier & VectorizeArgTypes)
287 vecArgTy = wrapAsVector(arg0Ty);
288
289 // Determine the intrinsic result type: `VectorizeRetType` returns a
290 // vector; otherwise, if data args are vectorized and `AddRetType` is
291 // unset, use a vector return with the same shape as those args.
292 mlir::Type funcResTy = resultTy;
293 if (modifier & VectorizeRetType)
294 funcResTy = wrapAsVector(resultTy);
295 else if (vecArgTy && !(modifier & AddRetType))
296 funcResTy = wrapAsVector(resultTy);
297
298 // AdvSIMD_2Arg_Scalar_Narrow_Intrinsic in IntrinsicsAArch64.td models
299 // operand 0 as LLVMExtendedType<0>: the result vector's lane count with
300 // double-width elements. Reconstruct that LLVM operand type from the Clang
301 // builtin's scalar argument type.
302 if (modifier & ArgAsWidenedRetType) {
303 auto resVecTy = mlir::dyn_cast<cir::VectorType>(funcResTy);
304 assert(resVecTy &&
305 "SISD LLVM argument reconstruction requires a vector result");
306 vecArgTy = cir::VectorType::get(arg0Ty, resVecTy.getSize());
307 }
308
309 // True if `ty` is arg0's type, or an integer of the same width that only
310 // differs in signedness. vsqadd/vuqadd mix the two on purpose: vsqaddb_u8
311 // takes a uint8_t and an int8_t, but both become the same vector type.
312 auto matchesArg0Ty = [&](mlir::Type ty) {
313 if (ty == arg0Ty)
314 return true;
315 auto intTy = mlir::dyn_cast<cir::IntType>(ty);
316 auto arg0IntTy = mlir::dyn_cast<cir::IntType>(arg0Ty);
317 return intTy && arg0IntTy && intTy.getWidth() == arg0IntTy.getWidth();
318 };
319
320 // `vecArgTy` is populated by `VectorizeArgTypes` or
321 // `ArgAsWidenedRetType`. When set, wrap every non-immediate data operand
322 // that has the same scalar type as arg0. Checking the ICE bitmap prevents
323 // an i32 immediate from being vectorized when it has the same type as a
324 // data operand (e.g. vqshrns_n_s32). `VectorizeImmArg` marks the entries
325 // whose trailing immediate must be widened as well.
326 const bool widenTrailingImm = vecArgTy && ops.size() == 2 &&
327 (modifier & VectorizeImmArg) &&
328 (iceArguments & (1U << 1));
330 argTypes.reserve(ops.size());
331 for (unsigned i = 0, e = ops.size(); i != e; ++i) {
332 bool isImmediate = iceArguments & (1U << i);
333 bool asVector =
334 vecArgTy && ((!isImmediate && matchesArg0Ty(ops[i].getType())) ||
335 (widenTrailingImm && i == 1));
336 argTypes.push_back(asVector ? mlir::Type(vecArgTy) : ops[i].getType());
337 }
338
339 return {funcResTy, std::move(argTypes)};
340}
341
342// Source-operand vector type for a common NEON binary intrinsic: the
343// double-element-width form of `vTy` when `ArgAsWidenedRetType` is set (e.g.
344// vraddhn), otherwise `vTy`.
345static cir::VectorType deriveNeonBinaryArgType(CIRGenBuilderTy &builder,
346 unsigned modifier,
347 cir::VectorType vTy) {
348 if (modifier & ArgAsWidenedRetType)
350 /*isExtended=*/true);
351 return vTy;
352}
353
354/// Create a vector from an input scalar argument, usually for a NEON SISD
355/// intrinsic call. Insert the argument into lane 0 of a poison vector.
356static void vecExtendIntValue(CIRGenFunction &cgf, cir::VectorType argVTy,
357 mlir::Value &arg, mlir::Location loc) {
358 CIRGenBuilderTy &builder = cgf.getBuilder();
359 // TODO: Support floating-point scalar arguments when a SISD intrinsic
360 // requires scalar-to-vector adaptation; current users are integer-only.
361 cir::IntType eltTy = mlir::dyn_cast<cir::IntType>(argVTy.getElementType());
362 assert(mlir::isa<cir::IntType>(arg.getType()) && eltTy);
363 // Cast the scalar data operand to the vector element type before inserting
364 // it into lane 0.
365 arg = builder.createIntCast(arg, eltTy);
366 mlir::Value zero = builder.getConstInt(loc, cgf.sizeTy, 0);
367 mlir::Value poison = builder.getConstant(loc, cir::PoisonAttr::get(argVTy));
368 arg = cir::VecInsertOp::create(builder, loc, poison, arg, zero);
369}
370
371static mlir::Value
373 const ARMNeonVectorIntrinsicInfo &info,
375 const CallExpr *expr, unsigned iceArguments) {
376 assert(info.LLVMIntrinsic && "Generic code assumes a valid intrinsic");
377
378 switch (info.BuiltinID) {
379 case NEON::BI__builtin_neon_vcled_s64:
380 case NEON::BI__builtin_neon_vcled_u64:
381 case NEON::BI__builtin_neon_vcles_f32:
382 case NEON::BI__builtin_neon_vcled_f64:
383 case NEON::BI__builtin_neon_vcltd_s64:
384 case NEON::BI__builtin_neon_vcltd_u64:
385 case NEON::BI__builtin_neon_vclts_f32:
386 case NEON::BI__builtin_neon_vcltd_f64:
387 case NEON::BI__builtin_neon_vcales_f32:
388 case NEON::BI__builtin_neon_vcaled_f64:
389 case NEON::BI__builtin_neon_vcalts_f32:
390 case NEON::BI__builtin_neon_vcaltd_f64:
391 cgf.cgm.errorNYI(expr->getSourceRange(),
392 std::string("unimplemented AArch64 builtin call: ") +
393 cgf.getContext().BuiltinInfo.getName(info.BuiltinID));
394 break;
395 }
396
397 unsigned intr = info.LLVMIntrinsic;
398
399 // Use fptosi.sat/fptoui.sat unless under strict FP.
401 if (intr == Intrinsic::aarch64_neon_fcvtzs)
402 intr = Intrinsic::fptosi_sat;
403 else if (intr == Intrinsic::aarch64_neon_fcvtzu)
404 intr = Intrinsic::fptoui_sat;
405
406 llvm::StringRef llvmIntrName =
407 getLLVMIntrNameNoPrefix(static_cast<llvm::Intrinsic::ID>(intr));
408 mlir::Location loc = cgf.getLoc(expr->getExprLoc());
409
410 // The switch stmt is intended to help catch NYI cases and will be removed
411 // once the CIR implementation is complete. Avoid adding specialized
412 // code in cases - that should only be required for a handful of examples.
413 switch (info.BuiltinID) {
414 default:
415 cgf.cgm.errorNYI(expr->getSourceRange(),
416 std::string("unimplemented AArch64 builtin call: ") +
417 cgf.getContext().BuiltinInfo.getName(info.BuiltinID));
418 break;
419 case NEON::BI__builtin_neon_vminv_s8:
420 case NEON::BI__builtin_neon_vminvq_s8:
421 case NEON::BI__builtin_neon_vminv_s16:
422 case NEON::BI__builtin_neon_vminvq_s16:
423 case NEON::BI__builtin_neon_vminv_s32:
424 case NEON::BI__builtin_neon_vminvq_s32:
425 case NEON::BI__builtin_neon_vminv_u8:
426 case NEON::BI__builtin_neon_vminvq_u8:
427 case NEON::BI__builtin_neon_vminv_u16:
428 case NEON::BI__builtin_neon_vminvq_u16:
429 case NEON::BI__builtin_neon_vminv_u32:
430 case NEON::BI__builtin_neon_vminvq_u32:
431 case NEON::BI__builtin_neon_vminv_f32:
432 case NEON::BI__builtin_neon_vminvq_f32:
433 case NEON::BI__builtin_neon_vminvq_f64:
434 case NEON::BI__builtin_neon_vminnmv_f32:
435 case NEON::BI__builtin_neon_vminnmvq_f32:
436 case NEON::BI__builtin_neon_vminnmvq_f64:
437 case NEON::BI__builtin_neon_vabdd_f64:
438 case NEON::BI__builtin_neon_vabds_f32:
439 case NEON::BI__builtin_neon_vshld_s64:
440 case NEON::BI__builtin_neon_vshld_u64:
441 case NEON::BI__builtin_neon_vpmins_f32:
442 case NEON::BI__builtin_neon_vpminqd_f64:
443 case NEON::BI__builtin_neon_vpminnms_f32:
444 case NEON::BI__builtin_neon_vpminnmqd_f64:
445 case NEON::BI__builtin_neon_vcvtd_s32_f64:
446 case NEON::BI__builtin_neon_vcvtd_s64_f64:
447 case NEON::BI__builtin_neon_vcvtd_u64_f64:
448 case NEON::BI__builtin_neon_vcvtd_u32_f64:
449 case NEON::BI__builtin_neon_vcvts_n_f32_s32:
450 case NEON::BI__builtin_neon_vcvts_n_f32_u32:
451 case NEON::BI__builtin_neon_vcvts_n_s32_f32:
452 case NEON::BI__builtin_neon_vcvts_n_u32_f32:
453 case NEON::BI__builtin_neon_vcvtd_n_f64_s64:
454 case NEON::BI__builtin_neon_vcvtd_n_f64_u64:
455 case NEON::BI__builtin_neon_vcvtd_n_s64_f64:
456 case NEON::BI__builtin_neon_vcvtd_n_u64_f64:
457 case NEON::BI__builtin_neon_vcvts_s32_f32:
458 case NEON::BI__builtin_neon_vcvts_s64_f32:
459 case NEON::BI__builtin_neon_vcvts_u32_f32:
460 case NEON::BI__builtin_neon_vcvts_u64_f32:
461 case NEON::BI__builtin_neon_vcvtns_s32_f32:
462 case NEON::BI__builtin_neon_vcvtns_s64_f32:
463 case NEON::BI__builtin_neon_vcvtns_u32_f32:
464 case NEON::BI__builtin_neon_vcvtns_u64_f32:
465 case NEON::BI__builtin_neon_vcvtnd_s32_f64:
466 case NEON::BI__builtin_neon_vcvtnd_s64_f64:
467 case NEON::BI__builtin_neon_vcvtnd_u32_f64:
468 case NEON::BI__builtin_neon_vcvtnd_u64_f64:
469 case NEON::BI__builtin_neon_vcvtms_s32_f32:
470 case NEON::BI__builtin_neon_vcvtms_s64_f32:
471 case NEON::BI__builtin_neon_vcvtms_u32_f32:
472 case NEON::BI__builtin_neon_vcvtms_u64_f32:
473 case NEON::BI__builtin_neon_vcvtmd_s32_f64:
474 case NEON::BI__builtin_neon_vcvtmd_u32_f64:
475 case NEON::BI__builtin_neon_vcvtmd_s64_f64:
476 case NEON::BI__builtin_neon_vcvtmd_u64_f64:
477 case NEON::BI__builtin_neon_vcvtps_s32_f32:
478 case NEON::BI__builtin_neon_vcvtps_s64_f32:
479 case NEON::BI__builtin_neon_vcvtps_u32_f32:
480 case NEON::BI__builtin_neon_vcvtps_u64_f32:
481 case NEON::BI__builtin_neon_vcvtpd_s32_f64:
482 case NEON::BI__builtin_neon_vcvtpd_u32_f64:
483 case NEON::BI__builtin_neon_vcvtpd_s64_f64:
484 case NEON::BI__builtin_neon_vcvtpd_u64_f64:
485 case NEON::BI__builtin_neon_vcvtas_s32_f32:
486 case NEON::BI__builtin_neon_vcvtas_s64_f32:
487 case NEON::BI__builtin_neon_vcvtas_u32_f32:
488 case NEON::BI__builtin_neon_vcvtas_u64_f32:
489 case NEON::BI__builtin_neon_vcvtad_s32_f64:
490 case NEON::BI__builtin_neon_vcvtad_u32_f64:
491 case NEON::BI__builtin_neon_vcvtad_s64_f64:
492 case NEON::BI__builtin_neon_vcvtad_u64_f64:
493 case NEON::BI__builtin_neon_vcvtxd_f32_f64:
494 case NEON::BI__builtin_neon_vaddlv_s32:
495 case NEON::BI__builtin_neon_vaddlv_u32:
496 case NEON::BI__builtin_neon_vaddlvq_s32:
497 case NEON::BI__builtin_neon_vaddlvq_u32:
498 case NEON::BI__builtin_neon_vaddv_s8:
499 case NEON::BI__builtin_neon_vaddv_s16:
500 case NEON::BI__builtin_neon_vaddv_s32:
501 case NEON::BI__builtin_neon_vaddv_u8:
502 case NEON::BI__builtin_neon_vaddv_u16:
503 case NEON::BI__builtin_neon_vaddv_u32:
504 case NEON::BI__builtin_neon_vaddv_f32:
505 case NEON::BI__builtin_neon_vaddvq_s8:
506 case NEON::BI__builtin_neon_vaddvq_s16:
507 case NEON::BI__builtin_neon_vaddvq_s32:
508 case NEON::BI__builtin_neon_vaddvq_s64:
509 case NEON::BI__builtin_neon_vaddvq_u8:
510 case NEON::BI__builtin_neon_vaddvq_u16:
511 case NEON::BI__builtin_neon_vaddvq_u32:
512 case NEON::BI__builtin_neon_vaddvq_u64:
513 case NEON::BI__builtin_neon_vaddvq_f32:
514 case NEON::BI__builtin_neon_vaddvq_f64:
515 case NEON::BI__builtin_neon_vabdh_f16:
516 case NEON::BI__builtin_neon_vrecpeh_f16:
517 case NEON::BI__builtin_neon_vrecpxh_f16:
518 case NEON::BI__builtin_neon_vrsqrteh_f16:
519 case NEON::BI__builtin_neon_vrsqrtsh_f16:
520 case NEON::BI__builtin_neon_vmaxv_s8:
521 case NEON::BI__builtin_neon_vmaxvq_s8:
522 case NEON::BI__builtin_neon_vmaxv_s16:
523 case NEON::BI__builtin_neon_vmaxvq_s16:
524 case NEON::BI__builtin_neon_vmaxv_s32:
525 case NEON::BI__builtin_neon_vmaxvq_s32:
526 case NEON::BI__builtin_neon_vmaxv_u8:
527 case NEON::BI__builtin_neon_vmaxvq_u8:
528 case NEON::BI__builtin_neon_vmaxv_u16:
529 case NEON::BI__builtin_neon_vmaxvq_u16:
530 case NEON::BI__builtin_neon_vmaxv_u32:
531 case NEON::BI__builtin_neon_vmaxvq_u32:
532 case NEON::BI__builtin_neon_vmaxv_f32:
533 case NEON::BI__builtin_neon_vmaxvq_f32:
534 case NEON::BI__builtin_neon_vmaxvq_f64:
535 case NEON::BI__builtin_neon_vqrshrund_n_s64:
536 case NEON::BI__builtin_neon_vqrshrnd_n_s64:
537 case NEON::BI__builtin_neon_vqrshrnd_n_u64:
538 case NEON::BI__builtin_neon_vqshrund_n_s64:
539 case NEON::BI__builtin_neon_vqshrnd_n_s64:
540 case NEON::BI__builtin_neon_vqshrnd_n_u64:
541 case NEON::BI__builtin_neon_vmaxnmv_f32:
542 case NEON::BI__builtin_neon_vmaxnmvq_f32:
543 case NEON::BI__builtin_neon_vmaxnmvq_f64:
544 case NEON::BI__builtin_neon_vsrid_n_s64:
545 case NEON::BI__builtin_neon_vsrid_n_u64:
546 case NEON::BI__builtin_neon_vslid_n_s64:
547 case NEON::BI__builtin_neon_vslid_n_u64:
548 case NEON::BI__builtin_neon_vpmaxs_f32:
549 case NEON::BI__builtin_neon_vpmaxqd_f64:
550 case NEON::BI__builtin_neon_vpmaxnms_f32:
551 case NEON::BI__builtin_neon_vpmaxnmqd_f64:
552 case NEON::BI__builtin_neon_vmulxh_f16:
553 case NEON::BI__builtin_neon_vqshrunh_n_s16:
554 case NEON::BI__builtin_neon_vqshruns_n_s32:
555 case NEON::BI__builtin_neon_vqshrnh_n_s16:
556 case NEON::BI__builtin_neon_vqshrns_n_s32:
557 case NEON::BI__builtin_neon_vqshrnh_n_u16:
558 case NEON::BI__builtin_neon_vqshrns_n_u32:
559 case NEON::BI__builtin_neon_vqsubb_s8:
560 case NEON::BI__builtin_neon_vqsubb_u8:
561 case NEON::BI__builtin_neon_vqsubh_s16:
562 case NEON::BI__builtin_neon_vqsubh_u16:
563 case NEON::BI__builtin_neon_vqsubs_s32:
564 case NEON::BI__builtin_neon_vqsubs_u32:
565 case NEON::BI__builtin_neon_vqsubd_s64:
566 case NEON::BI__builtin_neon_vqsubd_u64:
567 case NEON::BI__builtin_neon_vqaddb_s8:
568 case NEON::BI__builtin_neon_vqaddb_u8:
569 case NEON::BI__builtin_neon_vqaddh_s16:
570 case NEON::BI__builtin_neon_vqaddh_u16:
571 case NEON::BI__builtin_neon_vqadds_s32:
572 case NEON::BI__builtin_neon_vqadds_u32:
573 case NEON::BI__builtin_neon_vqaddd_s64:
574 case NEON::BI__builtin_neon_vqaddd_u64:
575 case NEON::BI__builtin_neon_vsqaddb_u8:
576 case NEON::BI__builtin_neon_vsqaddh_u16:
577 case NEON::BI__builtin_neon_vsqadds_u32:
578 case NEON::BI__builtin_neon_vsqaddd_u64:
579 case NEON::BI__builtin_neon_vuqaddb_s8:
580 case NEON::BI__builtin_neon_vuqaddh_s16:
581 case NEON::BI__builtin_neon_vuqadds_s32:
582 case NEON::BI__builtin_neon_vuqaddd_s64:
583 case NEON::BI__builtin_neon_vqrshrns_n_s32:
584 case NEON::BI__builtin_neon_vqrshrns_n_u32:
585 case NEON::BI__builtin_neon_vqrshrnh_n_s16:
586 case NEON::BI__builtin_neon_vqrshrnh_n_u16:
587 case NEON::BI__builtin_neon_vqrshruns_n_s32:
588 case NEON::BI__builtin_neon_vqrshrunh_n_s16:
589 case NEON::BI__builtin_neon_vqshlb_s8:
590 case NEON::BI__builtin_neon_vqshlb_u8:
591 case NEON::BI__builtin_neon_vqshlh_s16:
592 case NEON::BI__builtin_neon_vqshlh_u16:
593 case NEON::BI__builtin_neon_vqshls_s32:
594 case NEON::BI__builtin_neon_vqshls_u32:
595 case NEON::BI__builtin_neon_vqshld_s64:
596 case NEON::BI__builtin_neon_vqshld_u64:
597 case NEON::BI__builtin_neon_vqshlb_n_s8:
598 case NEON::BI__builtin_neon_vqshlb_n_u8:
599 case NEON::BI__builtin_neon_vqshlh_n_s16:
600 case NEON::BI__builtin_neon_vqshlh_n_u16:
601 case NEON::BI__builtin_neon_vqshls_n_s32:
602 case NEON::BI__builtin_neon_vqshls_n_u32:
603 case NEON::BI__builtin_neon_vqshlub_n_s8:
604 case NEON::BI__builtin_neon_vqshluh_n_s16:
605 case NEON::BI__builtin_neon_vqshlus_n_s32:
606 break;
607 }
608
609 CIRGenBuilderTy &builder = cgf.getBuilder();
610 mlir::Type arg0Ty = cgf.convertType(expr->getArg(0)->getType());
611 mlir::Type resultTy = cgf.convertType(expr->getType());
612
613 // Derive per-operand argument types and the result type from the
614 // TypeModifier flags. `emitNeonCall` takes care of per-operand
615 // bitcasts to `argTypes`.
616 auto [funcResTy, argTypes] = deriveNeonSISDIntrinsicOperandTypes(
617 cgf, info.TypeModifier, arg0Ty, resultTy, ops, iceArguments);
618
619 assert(argTypes.size() == ops.size());
620 for (unsigned i = 0, e = ops.size(); i != e; ++i) {
621 if (cgf.cgm.getDataLayout().getTypeSizeInBits(ops[i].getType()) ==
622 cgf.cgm.getDataLayout().getTypeSizeInBits(argTypes[i]))
623 continue;
624
625 auto argVecTy = mlir::dyn_cast<cir::VectorType>(argTypes[i]);
626 assert(argVecTy && !mlir::isa<cir::VectorType>(ops[i].getType()) &&
627 "expecting vector LLVM intrinsic type and scalar Clang builtin "
628 "type");
629
630 vecExtendIntValue(cgf, argVecTy, ops[i], loc);
631 }
632
633 mlir::Value result = emitNeonCall(cgf.cgm, builder, std::move(argTypes), ops,
634 llvmIntrName, funcResTy, loc);
635
636 if (cgf.cgm.getDataLayout().getTypeSizeInBits(resultTy) <
637 cgf.cgm.getDataLayout().getTypeSizeInBits(funcResTy)) {
638
639 assert(mlir::isa<cir::VectorType>(result.getType()));
640 return cir::VecExtractOp::create(builder, loc, result,
641 builder.getConstInt(loc, cgf.sizeTy, 0));
642 }
643
644 return builder.createBitcast(loc, result, resultTy);
645}
646
647//===----------------------------------------------------------------------===//
648// Emit-helpers
649//===----------------------------------------------------------------------===//
650static mlir::Value
652 mlir::Location loc, mlir::Value src,
653 mlir::Type retTy, const cir::CmpOpKind kind) {
654
655 bool scalarCmp = !isa<cir::VectorType>(src.getType());
656 if (!scalarCmp) {
657 assert(!cast<cir::VectorType>(retTy).getIsScalable() &&
658 "This is only intended for fixed-width vectors");
659 // Vector types are cast to i8 vectors. Recover original type.
660 src = builder.createBitcast(src, retTy);
661 }
662
663 mlir::Value zero = builder.getNullValue(src.getType(), loc);
664
665 if (!scalarCmp)
666 return builder.createVecCompare(loc, kind, src, zero);
667
668 // For scalars, cast !cir.bool to !cir.int<s, 1> so that the compare
669 // result is sign- rather zero-extended when casting to the output
670 // retType.
671 mlir::Value cmp = builder.createCast(
672 loc, cir::CastKind::bool_to_int,
673 builder.createCompare(loc, kind, src, zero), builder.getSIntNTy(1));
674
675 return builder.createCast(loc, cir::CastKind::integral, cmp, retTy);
676}
677
678static cir::VectorType getNeonType(CIRGenFunction *cgf, NeonTypeFlags typeFlags,
679 bool hasLegalHalfType = true,
680 bool v1Ty = false,
681 bool allowBFloatArgsAndRet = true) {
682 int isQuad = typeFlags.isQuad();
683 switch (typeFlags.getEltType()) {
686 return cir::VectorType::get(typeFlags.isUnsigned() ? cgf->uInt8Ty
687 : cgf->sInt8Ty,
688 v1Ty ? 1 : (8 << isQuad));
690 return cir::VectorType::get(cgf->uInt8Ty, v1Ty ? 1 : (8 << isQuad));
693 return cir::VectorType::get(typeFlags.isUnsigned() ? cgf->uInt16Ty
694 : cgf->sInt16Ty,
695 v1Ty ? 1 : (4 << isQuad));
697 if (allowBFloatArgsAndRet)
698 return cir::VectorType::get(cgf->getCIRGenModule().bFloat16Ty,
699 v1Ty ? 1 : (4 << isQuad));
700 return cir::VectorType::get(cgf->uInt16Ty, v1Ty ? 1 : (4 << isQuad));
702 if (hasLegalHalfType)
703 return cir::VectorType::get(cgf->getCIRGenModule().fP16Ty,
704 v1Ty ? 1 : (4 << isQuad));
705 return cir::VectorType::get(cgf->uInt16Ty, v1Ty ? 1 : (4 << isQuad));
707 return cir::VectorType::get(typeFlags.isUnsigned() ? cgf->uInt32Ty
708 : cgf->sInt32Ty,
709 v1Ty ? 1 : (2 << isQuad));
712 return cir::VectorType::get(typeFlags.isUnsigned() ? cgf->uInt64Ty
713 : cgf->sInt64Ty,
714 v1Ty ? 1 : (1 << isQuad));
716 // FIXME: i128 and f128 doesn't get fully support in Clang and llvm.
717 // There is a lot of i128 and f128 API missing.
718 // so we use v16i8 to represent poly128 and get pattern matched.
719 return cir::VectorType::get(cgf->uInt8Ty, 16);
721 return cir::VectorType::get(cgf->getCIRGenModule().floatTy,
722 v1Ty ? 1 : (2 << isQuad));
724 return cir::VectorType::get(cgf->getCIRGenModule().doubleTy,
725 v1Ty ? 1 : (1 << isQuad));
726 }
727 llvm_unreachable("Unknown vector element type!");
728}
729
730static mlir::Value emitNeonSplat(CIRGenBuilderTy &builder, mlir::Location loc,
731 mlir::Value v, mlir::Value lane,
732 unsigned int resEltCnt) {
733 assert(isa<cir::ConstantOp>(lane.getDefiningOp()) &&
734 "lane number is not a constant!");
735 int64_t laneCst = getIntValueFromConstOp(lane);
736 llvm::SmallVector<int64_t, 4> shuffleMask(resEltCnt, laneCst);
737 return builder.createVecShuffle(loc, v, shuffleMask);
738}
739
740/// Flip the signedness of `vecTy`'s element type, keeping the width and
741/// number of lanes the same. Used when a NEON intrinsic takes a shift
742/// amount vector that must be signed (e.g. aarch64.neon.urshl takes a
743/// signed amount even though the data vector is unsigned).
744static cir::VectorType getSignChangedVectorType(CIRGenBuilderTy &builder,
745 cir::VectorType vecTy) {
746 auto elemTy = mlir::cast<cir::IntType>(vecTy.getElementType());
747 elemTy = elemTy.isSigned() ? builder.getUIntNTy(elemTy.getWidth())
748 : builder.getSIntNTy(elemTy.getWidth());
749 return cir::VectorType::get(elemTy, vecTy.getSize());
750}
751
752static mlir::Value emitCommonNeonShift(CIRGenBuilderTy &builder,
753 mlir::Location loc,
754 cir::VectorType resTy,
755 mlir::Value shifTgt,
756 mlir::Value shiftAmt, bool shiftLeft) {
757 shiftAmt = emitNeonShiftVector(builder, shiftAmt, resTy, loc, /*neg=*/false);
758 return cir::ShiftOp::create(builder, loc, resTy,
759 builder.createBitcast(shifTgt, resTy), shiftAmt,
760 shiftLeft);
761}
762
763// Right-shift a vector by a constant.
764static mlir::Value emitNeonRShiftImm(CIRGenFunction &cgf, mlir::Value shiftVec,
765 mlir::Value shiftVal,
766 cir::VectorType vecTy, bool usgn,
767 mlir::Location loc) {
768 CIRGenBuilderTy &builder = cgf.getBuilder();
769 int64_t shiftAmt = getIntValueFromConstOp(shiftVal);
770 int eltSize =
771 cgf.cgm.getDataLayout().getTypeSizeInBits(vecTy.getElementType());
772
773 shiftVec = builder.createBitcast(shiftVec, vecTy);
774 // lshr/ashr are undefined when the shift amount is equal to the vector
775 // element size.
776 if (shiftAmt == eltSize) {
777 if (usgn) {
778 // Right-shifting an unsigned value by its size yields 0.
779 return builder.getZero(loc, vecTy);
780 }
781 // Right-shifting a signed value by its size is equivalent
782 // to a shift of size-1.
783 --shiftAmt;
784 shiftVal = builder.getConstInt(loc, vecTy.getElementType(), shiftAmt);
785 }
786 return emitCommonNeonShift(builder, loc, vecTy, shiftVec, shiftVal,
787 /*shiftLeft=*/false);
788}
789
790static cir::VectorType getIntVecFromVecTy(CIRGenBuilderTy &builder,
791 cir::VectorType vecTy) {
792 if (!cir::isAnyFloatingPointType(vecTy.getElementType()))
793 return vecTy;
794
795 if (mlir::isa<cir::SingleType>(vecTy.getElementType()))
796 return cir::VectorType::get(builder.getSInt32Ty(), vecTy.getSize());
797 if (mlir::isa<cir::DoubleType>(vecTy.getElementType()))
798 return cir::VectorType::get(builder.getSInt64Ty(), vecTy.getSize());
799 llvm_unreachable(
800 "Unsupported element type in getVecOfIntTypeWithSameEltWidth");
801}
802
803/// The vld1_xN builtins move their data through an aggregate of N vectors.
804/// Return N, or 0 if `builtinID` is not one of them.
805static unsigned getNeonMultiVecCount(unsigned builtinID) {
806 switch (builtinID) {
807 default:
808 return 0;
809 case NEON::BI__builtin_neon_vld1_x2_v:
810 case NEON::BI__builtin_neon_vld1q_x2_v:
811 return 2;
812 case NEON::BI__builtin_neon_vld1_x3_v:
813 case NEON::BI__builtin_neon_vld1q_x3_v:
814 return 3;
815 case NEON::BI__builtin_neon_vld1_x4_v:
816 case NEON::BI__builtin_neon_vld1q_x4_v:
817 return 4;
818 }
819}
820
821/// Return the anonymous record type `{vecTy, ..., vecTy}` (`numVecs` members)
822/// modelling the struct returned by LLVM's multi-vector NEON load intrinsics.
824 mlir::Type vecTy, unsigned numVecs) {
825 llvm::SmallVector<mlir::Type> members(numVecs, vecTy);
826 return builder.getAnonRecordTy(members, /*packed=*/false,
828}
829
830/// Call the multi-vector NEON load intrinsic `llvmIntrinsic` with `args` of
831/// `argTypes` and store the resulting `numVecs`-vector aggregate to the
832/// destination pointer `dest`. Mirrors the `CreateCall` +
833/// `CreateDefaultAlignedStore` pair used for `vld1_xN` in
834/// `EmitCommonNeonBuiltinExpr` and for `vld[234]{,_dup,_lane}` in
835/// `EmitAArch64BuiltinExpr` (ARM.cpp).
836static mlir::Value
840 llvm::Intrinsic::ID llvmIntrinsic, mlir::Type ty,
841 unsigned numVecs, mlir::Location loc) {
842 CIRGenBuilderTy &builder = cgf.getBuilder();
843 cir::RecordType recTy = getNeonMultiVecTy(builder, ty, numVecs);
844 mlir::Value result =
845 emitNeonCall(cgf.getCIRGenModule(), builder, std::move(argTypes), args,
846 getLLVMIntrNameNoPrefix(llvmIntrinsic), recTy, loc);
847 Address destAddr(builder.createPtrBitcast(dest, recTy), recTy,
849 cgf.cgm.getDataLayout().getABITypeAlign(recTy)));
850 builder.createStore(loc, result, destAddr);
851 return nullptr;
852}
853
854/// Emit a multi-vector NEON load: call `llvmIntrinsic` on the source pointer
855/// `ops[1]` and store the resulting aggregate to the destination pointer
856/// `ops[0]`.
857static mlir::Value emitNeonMultiVecLoad(CIRGenFunction &cgf,
859 unsigned llvmIntrinsic, mlir::Type ty,
860 unsigned numVecs, mlir::Location loc) {
861 llvm::SmallVector<mlir::Value> srcOp = {ops[1]};
863 cgf, ops[0], {cgf.getBuilder().getVoidPtrTy()}, srcOp,
864 static_cast<llvm::Intrinsic::ID>(llvmIntrinsic), ty, numVecs, loc);
865}
866
867/// Emit a multi-vector NEON load-lane: call `llvmIntrinsic` on the `numVecs`
868/// vector operands, the lane index, and the source pointer `ops[1]`, then
869/// store the resulting aggregate to the destination pointer `ops[0]`.
870/// `ops` on entry is `[dest, addr, vec0, ..., vec(numVecs-1), lane]`.
873 llvm::Intrinsic::ID llvmIntrinsic,
874 mlir::Type ty, unsigned numVecs,
875 mlir::Location loc) {
876 assert(ops.size() == numVecs + 3 && "expected [dest, addr, vecs..., lane]");
877 CIRGenBuilderTy &builder = cgf.getBuilder();
878 // Reorder to [vec0, ..., vec(numVecs-1), lane, addr] for the intrinsic call.
879 llvm::SmallVector<mlir::Value> callOps(ops.begin() + 2, ops.end());
880 callOps.push_back(ops[1]);
881 // The lane is a Sema-range-checked non-negative constant, so this
882 // sign-extending cast is equivalent to classic CodeGen's CreateZExt.
883 callOps[numVecs] = builder.createIntCast(callOps[numVecs], cgf.sInt64Ty);
884 llvm::SmallVector<mlir::Type> argTypes(numVecs, ty);
885 argTypes.push_back(cgf.sInt64Ty);
886 argTypes.push_back(builder.getVoidPtrTy());
887 return emitNeonMultiVecLoadCall(cgf, ops[0], std::move(argTypes), callOps,
888 llvmIntrinsic, ty, numVecs, loc);
889}
890
891static mlir::Value emitCommonNeonBuiltinExpr(
892 CIRGenFunction &cgf, unsigned builtinID, unsigned llvmIntrinsic,
893 unsigned altLLVMIntrinsic, const char *nameHint, unsigned modifier,
895 mlir::Location loc = cgf.getLoc(expr->getExprLoc());
896 clang::ASTContext &ctx = cgf.getContext();
897
898 // Extract the trailing immediate argument that encodes the type discriminator
899 // for this overloaded intrinsic.
900 // TODO: Move to the parent code that takes care of argument processing.
901 const clang::Expr *arg = expr->getArg(expr->getNumArgs() - 1);
902 std::optional<llvm::APSInt> neonTypeConst = arg->getIntegerConstantExpr(ctx);
903 if (!neonTypeConst)
904 return nullptr;
905
906 // Determine the type of this overloaded NEON intrinsic.
907 NeonTypeFlags neonType(neonTypeConst->getZExtValue());
908 const bool isUnsigned = neonType.isUnsigned();
909 const bool hasLegalHalfType = cgf.getTarget().hasFastHalfType();
910 const bool usgn = neonType.isUnsigned();
911 const bool isQuad = neonType.isQuad();
912
913 // The value of allowBFloatArgsAndRet is true for AArch64, but it should
914 // come from ABI info.
915 // TODO(cir): Use ABInfo to extract this information
916 const bool allowBFloatArgsAndRet = cgf.getTarget().hasFastHalfType();
917 // FIXME
918 // getTargetHooks().getABIInfo().allowBFloatArgsAndRet();
919
920 cir::VectorType vTy = getNeonType(&cgf, neonType, hasLegalHalfType,
921 /*v1Ty=*/false, allowBFloatArgsAndRet);
922 cir::VectorType ty = vTy;
923 if (!ty)
924 return nullptr;
925
926 switch (builtinID) {
927 case NEON::BI__builtin_neon_splat_lane_v:
928 case NEON::BI__builtin_neon_splat_laneq_v:
929 case NEON::BI__builtin_neon_splatq_lane_v:
930 case NEON::BI__builtin_neon_splatq_laneq_v: {
931 uint64_t numElements = vTy.getSize();
932 if (builtinID == NEON::BI__builtin_neon_splatq_lane_v)
933 numElements *= 2;
934 if (builtinID == NEON::BI__builtin_neon_splat_laneq_v)
935 numElements /= 2;
936 ops[0] = cgf.getBuilder().createBitcast(loc, ops[0], vTy);
937 return emitNeonSplat(cgf.getBuilder(), loc, ops[0], ops[1], numElements);
938 }
939 case NEON::BI__builtin_neon_vpadd_v:
940 case NEON::BI__builtin_neon_vpaddq_v:
941 case NEON::BI__builtin_neon_vabs_v:
942 case NEON::BI__builtin_neon_vabsq_v:
943 cgf.cgm.errorNYI(expr->getSourceRange(),
944 std::string("unimplemented AArch64 builtin call: ") +
945 ctx.BuiltinInfo.getName(builtinID));
946 return mlir::Value{};
947 case NEON::BI__builtin_neon_vadd_v:
948 case NEON::BI__builtin_neon_vaddq_v: {
949 unsigned numBytes = (builtinID == NEON::BI__builtin_neon_vaddq_v) ? 16 : 8;
950 cir::VectorType byteTy =
951 cir::VectorType::get(cgf.getBuilder().getUInt8Ty(), numBytes);
952 ops[0] = cgf.getBuilder().createBitcast(ops[0], byteTy);
953 ops[1] = cgf.getBuilder().createBitcast(ops[1], byteTy);
954 mlir::Value result = cgf.getBuilder().createXor(loc, ops[0], ops[1]);
955 return cgf.getBuilder().createBitcast(result, ty);
956 }
957 case NEON::BI__builtin_neon_vaddhn_v: {
958 // srcTy has double-width elements (e.g. <8 x i16> when VTy is <8 x i8>).
959 // Unsigned so createShiftRight emits lshr, not ashr.
960 cir::VectorType srcTy =
962 vTy, /*isExtended=*/true, /*isSigned=*/false);
963
964 // %sum = add <4 x i32> %lhs, %rhs
965 ops[0] = cgf.getBuilder().createBitcast(ops[0], srcTy);
966 ops[1] = cgf.getBuilder().createBitcast(ops[1], srcTy);
967 mlir::Value result = cgf.getBuilder().createAdd(loc, ops[0], ops[1]);
968
969 // %high = lshr <4 x i32> %sum, <i32 16, i32 16, i32 16, i32 16>
970 auto wideEltTy = mlir::cast<cir::IntType>(srcTy.getElementType());
971 mlir::Value shiftAmt = cgf.getBuilder().getConstantInt(
972 loc, wideEltTy, wideEltTy.getWidth() / 2);
973 mlir::Value shiftVec =
974 emitNeonShiftVector(cgf.getBuilder(), shiftAmt, srcTy, loc,
975 /*neg=*/false);
976 result = cgf.getBuilder().createShiftRight(loc, result, shiftVec);
977
978 // %res = trunc <4 x i32> %high to <4 x i16>
979 return cgf.getBuilder().createIntCast(result, vTy);
980 }
981 case NEON::BI__builtin_neon_vsubhn_v: {
982 // srcTy has double-width elements (e.g. <8 x i16> when VTy is <8 x i8>).
983 // Unsigned so createShiftRight emits lshr, not ashr.
984 cir::VectorType srcTy =
986 vTy, /*isExtended=*/true, /*isSigned=*/false);
987
988 // %diff = sub <4 x i32> %lhs, %rhs
989 ops[0] = cgf.getBuilder().createBitcast(ops[0], srcTy);
990 ops[1] = cgf.getBuilder().createBitcast(ops[1], srcTy);
991 mlir::Value result = cgf.getBuilder().createSub(loc, ops[0], ops[1]);
992
993 // %high = lshr <4 x i32> %diff, <i32 16, i32 16, i32 16, i32 16>
994 auto wideEltTy = mlir::cast<cir::IntType>(srcTy.getElementType());
995 mlir::Value shiftAmt = cgf.getBuilder().getConstantInt(
996 loc, wideEltTy, wideEltTy.getWidth() / 2);
997 mlir::Value shiftVec =
998 emitNeonShiftVector(cgf.getBuilder(), shiftAmt, srcTy, loc,
999 /*neg=*/false);
1000 result = cgf.getBuilder().createShiftRight(loc, result, shiftVec);
1001
1002 // %res = trunc <4 x i32> %high to <4 x i16>
1003 return cgf.getBuilder().createIntCast(result, vTy);
1004 }
1005 case NEON::BI__builtin_neon_vcale_v:
1006 case NEON::BI__builtin_neon_vcaleq_v:
1007 case NEON::BI__builtin_neon_vcalt_v:
1008 case NEON::BI__builtin_neon_vcaltq_v:
1009 case NEON::BI__builtin_neon_vcage_v:
1010 case NEON::BI__builtin_neon_vcageq_v:
1011 case NEON::BI__builtin_neon_vcagt_v:
1012 case NEON::BI__builtin_neon_vcagtq_v:
1013 cgf.cgm.errorNYI(expr->getSourceRange(),
1014 std::string("unimplemented AArch64 builtin call: ") +
1015 ctx.BuiltinInfo.getName(builtinID));
1016 return mlir::Value{};
1017 case NEON::BI__builtin_neon_vceqz_v:
1018 case NEON::BI__builtin_neon_vceqzq_v:
1019 return emitAArch64CompareBuiltinExpr(cgf, cgf.getBuilder(), loc, ops[0],
1020 vTy, cir::CmpOpKind::eq);
1021 case NEON::BI__builtin_neon_vcgez_v:
1022 case NEON::BI__builtin_neon_vcgezq_v:
1023 case NEON::BI__builtin_neon_vclez_v:
1024 case NEON::BI__builtin_neon_vclezq_v:
1025 case NEON::BI__builtin_neon_vcgtz_v:
1026 case NEON::BI__builtin_neon_vcgtzq_v:
1027 case NEON::BI__builtin_neon_vcltz_v:
1028 case NEON::BI__builtin_neon_vcltzq_v:
1029 case NEON::BI__builtin_neon_vclz_v:
1030 case NEON::BI__builtin_neon_vclzq_v:
1031 cgf.cgm.errorNYI(expr->getSourceRange(),
1032 std::string("unimplemented AArch64 builtin call: ") +
1033 ctx.BuiltinInfo.getName(builtinID));
1034 return mlir::Value{};
1035 case NEON::BI__builtin_neon_vcvt_f32_v:
1036 case NEON::BI__builtin_neon_vcvtq_f32_v: {
1037 ops[0] = cgf.getBuilder().createBitcast(ops[0], ty);
1038 ty = getNeonType(&cgf, NeonTypeFlags(NeonTypeFlags::Float32, false, isQuad),
1039 hasLegalHalfType);
1040 return cgf.getBuilder().createCast(cir::CastKind::int_to_float, ops[0], ty);
1041 }
1042 case NEON::BI__builtin_neon_vcvt_f16_s16:
1043 case NEON::BI__builtin_neon_vcvt_f16_u16:
1044 case NEON::BI__builtin_neon_vcvtq_f16_s16:
1045 case NEON::BI__builtin_neon_vcvtq_f16_u16:
1046 case NEON::BI__builtin_neon_vcvt_n_f16_s16:
1047 case NEON::BI__builtin_neon_vcvt_n_f16_u16:
1048 case NEON::BI__builtin_neon_vcvtq_n_f16_s16:
1049 case NEON::BI__builtin_neon_vcvtq_n_f16_u16:
1050 cgf.cgm.errorNYI(expr->getSourceRange(),
1051 std::string("unimplemented AArch64 builtin call: ") +
1052 ctx.BuiltinInfo.getName(builtinID));
1053 return mlir::Value{};
1054 case NEON::BI__builtin_neon_vcvt_n_f32_v:
1055 case NEON::BI__builtin_neon_vcvt_n_f64_v:
1056 case NEON::BI__builtin_neon_vcvtq_n_f32_v:
1057 case NEON::BI__builtin_neon_vcvtq_n_f64_v: {
1058 // The constant argument to an _n_ intrinsic always is Int32Ty.
1059 mlir::Type cstIntTy = cgf.sInt32Ty;
1060 llvm::StringRef llvmIntrName =
1061 getLLVMIntrNameNoPrefix(static_cast<llvm::Intrinsic::ID>(
1062 usgn ? llvmIntrinsic : altLLVMIntrinsic));
1063 return emitNeonCall(cgf.getCIRGenModule(), cgf.getBuilder(),
1064 /*argTypes=*/{vTy, cstIntTy}, ops, llvmIntrName,
1065 /*funcResTy=*/getFloatNeonType(cgf, neonType), loc);
1066 }
1067 case NEON::BI__builtin_neon_vcvt_n_s16_f16:
1068 case NEON::BI__builtin_neon_vcvt_n_s32_v:
1069 case NEON::BI__builtin_neon_vcvt_n_u16_f16:
1070 case NEON::BI__builtin_neon_vcvt_n_u32_v:
1071 case NEON::BI__builtin_neon_vcvt_n_s64_v:
1072 case NEON::BI__builtin_neon_vcvt_n_u64_v:
1073 case NEON::BI__builtin_neon_vcvtq_n_s16_f16:
1074 case NEON::BI__builtin_neon_vcvtq_n_s32_v:
1075 case NEON::BI__builtin_neon_vcvtq_n_u16_f16:
1076 case NEON::BI__builtin_neon_vcvtq_n_u32_v:
1077 case NEON::BI__builtin_neon_vcvtq_n_s64_v:
1078 case NEON::BI__builtin_neon_vcvtq_n_u64_v: {
1079 // The constant argument to an _n_ intrinsic always is Int32Ty.
1080 mlir::Type cstIntTy = cgf.sInt32Ty;
1081 llvm::StringRef llvmIntrName = getLLVMIntrNameNoPrefix(
1082 static_cast<llvm::Intrinsic::ID>(llvmIntrinsic));
1083 return emitNeonCall(
1084 cgf.getCIRGenModule(), cgf.getBuilder(),
1085 /*argTypes=*/{getFloatNeonType(cgf, neonType), cstIntTy}, ops,
1086 llvmIntrName,
1087 /*funcResTy=*/vTy, loc);
1088 }
1089 case NEON::BI__builtin_neon_vcvt_s32_v:
1090 case NEON::BI__builtin_neon_vcvt_u32_v:
1091 case NEON::BI__builtin_neon_vcvt_s64_v:
1092 case NEON::BI__builtin_neon_vcvt_u64_v:
1093 case NEON::BI__builtin_neon_vcvt_s16_f16:
1094 case NEON::BI__builtin_neon_vcvt_u16_f16:
1095 case NEON::BI__builtin_neon_vcvtq_s32_v:
1096 case NEON::BI__builtin_neon_vcvtq_u32_v:
1097 case NEON::BI__builtin_neon_vcvtq_s64_v:
1098 case NEON::BI__builtin_neon_vcvtq_u64_v:
1099 case NEON::BI__builtin_neon_vcvtq_s16_f16:
1100 case NEON::BI__builtin_neon_vcvtq_u16_f16: {
1101 auto ty = getFloatNeonType(cgf, neonType);
1102 // Undo the bitcast inserted by intrinsics that expand to this builtin
1103 // (e.g. vcvt_u32_f32).
1104 // TODO: While the bitcasts eventually cancel each other out, we should
1105 // avoid them altogether.
1106 ops[0] =
1107 cgf.getBuilder().createCast(loc, cir::CastKind::bitcast, ops[0], ty);
1109 // AArch64: use fptosi.sat/fptoui.sat unless under strict FP.
1110 llvm::StringRef llvmIntrName = usgn ? "fptoui.sat" : "fptosi.sat";
1111 return emitNeonCall(cgf.getCIRGenModule(), cgf.getBuilder(),
1112 /*argTypes=*/{ty}, ops, llvmIntrName, vTy, loc);
1113 }
1114 case NEON::BI__builtin_neon_vcvta_s16_f16:
1115 case NEON::BI__builtin_neon_vcvta_s32_v:
1116 case NEON::BI__builtin_neon_vcvta_s64_v:
1117 case NEON::BI__builtin_neon_vcvta_u16_f16:
1118 case NEON::BI__builtin_neon_vcvta_u32_v:
1119 case NEON::BI__builtin_neon_vcvta_u64_v:
1120 case NEON::BI__builtin_neon_vcvtaq_s16_f16:
1121 case NEON::BI__builtin_neon_vcvtaq_s32_v:
1122 case NEON::BI__builtin_neon_vcvtaq_s64_v:
1123 case NEON::BI__builtin_neon_vcvtaq_u16_f16:
1124 case NEON::BI__builtin_neon_vcvtaq_u32_v:
1125 case NEON::BI__builtin_neon_vcvtaq_u64_v:
1126 case NEON::BI__builtin_neon_vcvtn_s16_f16:
1127 case NEON::BI__builtin_neon_vcvtn_s32_v:
1128 case NEON::BI__builtin_neon_vcvtn_s64_v:
1129 case NEON::BI__builtin_neon_vcvtn_u16_f16:
1130 case NEON::BI__builtin_neon_vcvtn_u32_v:
1131 case NEON::BI__builtin_neon_vcvtn_u64_v:
1132 case NEON::BI__builtin_neon_vcvtnq_s16_f16:
1133 case NEON::BI__builtin_neon_vcvtnq_s32_v:
1134 case NEON::BI__builtin_neon_vcvtnq_s64_v:
1135 case NEON::BI__builtin_neon_vcvtnq_u16_f16:
1136 case NEON::BI__builtin_neon_vcvtnq_u32_v:
1137 case NEON::BI__builtin_neon_vcvtnq_u64_v:
1138 case NEON::BI__builtin_neon_vcvtp_s16_f16:
1139 case NEON::BI__builtin_neon_vcvtp_s32_v:
1140 case NEON::BI__builtin_neon_vcvtp_s64_v:
1141 case NEON::BI__builtin_neon_vcvtp_u16_f16:
1142 case NEON::BI__builtin_neon_vcvtp_u32_v:
1143 case NEON::BI__builtin_neon_vcvtp_u64_v:
1144 case NEON::BI__builtin_neon_vcvtpq_s16_f16:
1145 case NEON::BI__builtin_neon_vcvtpq_s32_v:
1146 case NEON::BI__builtin_neon_vcvtpq_s64_v:
1147 case NEON::BI__builtin_neon_vcvtpq_u16_f16:
1148 case NEON::BI__builtin_neon_vcvtpq_u32_v:
1149 case NEON::BI__builtin_neon_vcvtpq_u64_v:
1150 case NEON::BI__builtin_neon_vcvtm_s16_f16:
1151 case NEON::BI__builtin_neon_vcvtm_s32_v:
1152 case NEON::BI__builtin_neon_vcvtm_s64_v:
1153 case NEON::BI__builtin_neon_vcvtm_u16_f16:
1154 case NEON::BI__builtin_neon_vcvtm_u32_v:
1155 case NEON::BI__builtin_neon_vcvtm_u64_v:
1156 case NEON::BI__builtin_neon_vcvtmq_s16_f16:
1157 case NEON::BI__builtin_neon_vcvtmq_s32_v:
1158 case NEON::BI__builtin_neon_vcvtmq_s64_v:
1159 case NEON::BI__builtin_neon_vcvtmq_u16_f16:
1160 case NEON::BI__builtin_neon_vcvtmq_u32_v:
1161 case NEON::BI__builtin_neon_vcvtmq_u64_v:
1162 cgf.cgm.errorNYI(expr->getSourceRange(),
1163 std::string("unimplemented AArch64 builtin call: ") +
1164 ctx.BuiltinInfo.getName(builtinID));
1165 return mlir::Value{};
1166 case NEON::BI__builtin_neon_vcvtx_f32_v: {
1167 llvm::StringRef llvmIntrName = getLLVMIntrNameNoPrefix(
1168 static_cast<llvm::Intrinsic::ID>(llvmIntrinsic));
1169 auto v2f64 = cir::VectorType::get(cgf.cgm.doubleTy, 2);
1170 auto v2f32 = cir::VectorType::get(cgf.cgm.floatTy, 2);
1171 return emitNeonCall(cgf.getCIRGenModule(), cgf.getBuilder(),
1172 /*argTypes=*/{v2f64}, ops, llvmIntrName,
1173 /*funcResTy=*/v2f32, loc);
1174 }
1175 case NEON::BI__builtin_neon_vext_v:
1176 case NEON::BI__builtin_neon_vextq_v:
1177 cgf.cgm.errorNYI(expr->getSourceRange(),
1178 std::string("unimplemented AArch64 builtin call: ") +
1179 ctx.BuiltinInfo.getName(builtinID));
1180 return mlir::Value{};
1181 case NEON::BI__builtin_neon_vfma_v:
1182 case NEON::BI__builtin_neon_vfmaq_v: {
1183 // NEON intrinsic: vfma(q)(accumulator, multiplicand1, multiplicand2)
1184 // CIR fma: fma(multiplicand1, multiplicand2, accumulator)
1185 // Reorder arguments to match fma signature.
1186 mlir::Value op0 = cgf.getBuilder().createBitcast(ops[0], ty);
1187 mlir::Value op1 = cgf.getBuilder().createBitcast(ops[1], ty);
1188 mlir::Value op2 = cgf.getBuilder().createBitcast(ops[2], ty);
1189 llvm::SmallVector<mlir::Value> fmaOps = {op1, op2, op0};
1190 return emitNeonCallToOp<cir::FMAOp>(cgf.cgm, cgf.getBuilder(), {ty, ty, ty},
1191 fmaOps, std::nullopt, ty, loc);
1192 }
1193 case NEON::BI__builtin_neon_vld1_x2_v:
1194 case NEON::BI__builtin_neon_vld1q_x2_v:
1195 case NEON::BI__builtin_neon_vld1_x3_v:
1196 case NEON::BI__builtin_neon_vld1q_x3_v:
1197 case NEON::BI__builtin_neon_vld1_x4_v:
1198 case NEON::BI__builtin_neon_vld1q_x4_v:
1199 return emitNeonMultiVecLoad(cgf, ops, llvmIntrinsic, ty,
1200 getNeonMultiVecCount(builtinID), loc);
1201 case NEON::BI__builtin_neon_vld1_v:
1202 case NEON::BI__builtin_neon_vld1q_v:
1203 case NEON::BI__builtin_neon_vld2_v:
1204 case NEON::BI__builtin_neon_vld2q_v:
1205 case NEON::BI__builtin_neon_vld3_v:
1206 case NEON::BI__builtin_neon_vld3q_v:
1207 case NEON::BI__builtin_neon_vld4_v:
1208 case NEON::BI__builtin_neon_vld4q_v:
1209 case NEON::BI__builtin_neon_vld2_dup_v:
1210 case NEON::BI__builtin_neon_vld2q_dup_v:
1211 case NEON::BI__builtin_neon_vld3_dup_v:
1212 case NEON::BI__builtin_neon_vld3q_dup_v:
1213 case NEON::BI__builtin_neon_vld4_dup_v:
1214 case NEON::BI__builtin_neon_vld4q_dup_v:
1215 case NEON::BI__builtin_neon_vld1_dup_v:
1216 case NEON::BI__builtin_neon_vld1q_dup_v:
1217 case NEON::BI__builtin_neon_vld2_lane_v:
1218 case NEON::BI__builtin_neon_vld2q_lane_v:
1219 case NEON::BI__builtin_neon_vld3_lane_v:
1220 case NEON::BI__builtin_neon_vld3q_lane_v:
1221 case NEON::BI__builtin_neon_vld4_lane_v:
1222 case NEON::BI__builtin_neon_vld4q_lane_v:
1223 cgf.cgm.errorNYI(expr->getSourceRange(),
1224 std::string("Reached code-path for ARM builtin call ") +
1225 ctx.BuiltinInfo.getName(builtinID) +
1226 "(ARM builtins are not supported ATM)");
1227 return mlir::Value{};
1228 case NEON::BI__builtin_neon_vmovl_v: {
1229 cir::VectorType dTy =
1231 ty, /*isExtended=*/false, !usgn);
1232 ops[0] = cgf.getBuilder().createBitcast(loc, ops[0], dTy);
1233 return cgf.getBuilder().createIntCast(ops[0], ty);
1234 }
1235 case NEON::BI__builtin_neon_vmovn_v:
1236 case NEON::BI__builtin_neon_vmull_v:
1237 case NEON::BI__builtin_neon_vpadal_v:
1238 case NEON::BI__builtin_neon_vpadalq_v:
1239 cgf.cgm.errorNYI(expr->getSourceRange(),
1240 std::string("Reached code-path for ARM builtin call ") +
1241 ctx.BuiltinInfo.getName(builtinID) +
1242 "(ARM builtins are not supported ATM)");
1243 return mlir::Value{};
1244 case NEON::BI__builtin_neon_vpaddl_v:
1245 case NEON::BI__builtin_neon_vpaddlq_v: {
1246 llvm::StringRef llvmIntrName =
1247 getLLVMIntrNameNoPrefix(static_cast<llvm::Intrinsic::ID>(
1248 usgn ? llvmIntrinsic : altLLVMIntrinsic));
1249 return emitNeonCall(cgf.getCIRGenModule(), cgf.getBuilder(),
1250 /*argTypes=*/{getNeonPairwiseWidenInputType(vTy, usgn)},
1251 ops, llvmIntrName,
1252 /*funcResTy=*/vTy, loc);
1253 }
1254 case NEON::BI__builtin_neon_vqdmlal_v:
1255 case NEON::BI__builtin_neon_vqdmlsl_v:
1256 case NEON::BI__builtin_neon_vqdmulhq_lane_v:
1257 case NEON::BI__builtin_neon_vqdmulh_lane_v:
1258 case NEON::BI__builtin_neon_vqrdmulhq_lane_v:
1259 case NEON::BI__builtin_neon_vqrdmulh_lane_v:
1260 case NEON::BI__builtin_neon_vqdmulhq_laneq_v:
1261 case NEON::BI__builtin_neon_vqdmulh_laneq_v:
1262 case NEON::BI__builtin_neon_vqrdmulhq_laneq_v:
1263 case NEON::BI__builtin_neon_vqrdmulh_laneq_v:
1264 cgf.cgm.errorNYI(expr->getSourceRange(),
1265 std::string("unimplemented AArch64 builtin call: ") +
1266 ctx.BuiltinInfo.getName(builtinID));
1267 return mlir::Value{};
1268 case NEON::BI__builtin_neon_vqshl_n_v:
1269 case NEON::BI__builtin_neon_vqshlq_n_v: {
1270 llvm::StringRef intrName =
1271 usgn ? "aarch64.neon.uqshl" : "aarch64.neon.sqshl";
1272 return emitNeonCall(cgf.cgm, cgf.getBuilder(), {ty, ty}, ops, intrName, ty,
1273 loc, /*isConstrainedFPIntrinsic=*/false, /*shift=*/1,
1274 /*rightshift=*/false);
1275 }
1276 case NEON::BI__builtin_neon_vqshlu_n_v:
1277 case NEON::BI__builtin_neon_vqshluq_n_v:
1278 return emitNeonCall(cgf.cgm, cgf.getBuilder(), {ty, ty}, ops,
1279 "aarch64.neon.sqshlu", ty, loc,
1280 /*isConstrainedFPIntrinsic=*/false, /*shift=*/1,
1281 /*rightshift=*/false);
1282 case NEON::BI__builtin_neon_vrecpe_v:
1283 case NEON::BI__builtin_neon_vrecpeq_v:
1284 case NEON::BI__builtin_neon_vrsqrte_v:
1285 case NEON::BI__builtin_neon_vrsqrteq_v:
1286 cgf.cgm.errorNYI(expr->getSourceRange(),
1287 std::string("unimplemented AArch64 builtin call: ") +
1288 ctx.BuiltinInfo.getName(builtinID));
1289 return mlir::Value{};
1290 case NEON::BI__builtin_neon_vrndi_v:
1291 case NEON::BI__builtin_neon_vrndiq_v:
1293 return emitNeonCallToOp<cir::NearbyintOp>(cgf.cgm, cgf.getBuilder(), {ty},
1294 ops, std::nullopt, ty, loc);
1295 case NEON::BI__builtin_neon_vrshr_n_v:
1296 case NEON::BI__builtin_neon_vrshrq_n_v: {
1297 llvm::StringRef intrName =
1298 usgn ? "aarch64.neon.urshl" : "aarch64.neon.srshl";
1299 return emitNeonCall(
1300 cgf.cgm, cgf.getBuilder(),
1301 {ty, usgn ? getSignChangedVectorType(cgf.getBuilder(), ty) : ty}, ops,
1302 intrName, ty, loc, /*isConstrainedFPIntrinsic=*/false,
1303 /*shift=*/1,
1304 /*rightshift=*/true);
1305 }
1306 case NEON::BI__builtin_neon_vsha512hq_u64:
1307 case NEON::BI__builtin_neon_vsha512h2q_u64:
1308 case NEON::BI__builtin_neon_vsha512su0q_u64:
1309 case NEON::BI__builtin_neon_vsha512su1q_u64:
1310 cgf.cgm.errorNYI(expr->getSourceRange(),
1311 std::string("unimplemented AArch64 builtin call: ") +
1312 ctx.BuiltinInfo.getName(builtinID));
1313 return mlir::Value{};
1314 case NEON::BI__builtin_neon_vshl_n_v:
1315 case NEON::BI__builtin_neon_vshlq_n_v:
1316 return emitCommonNeonShift(cgf.getBuilder(), loc, vTy, ops[0], ops[1],
1317 /*shiftLeft=*/true);
1318 case NEON::BI__builtin_neon_vshll_n_v: {
1319 CIRGenBuilderTy &builder = cgf.getBuilder();
1320 cir::VectorType narrowVecTy =
1322 /*isExtended=*/false,
1323 /*isSigned=*/!usgn);
1324 mlir::Value src = builder.createBitcast(ops[0], narrowVecTy);
1325 mlir::Value extended = builder.createIntCast(src, vTy);
1326 return emitCommonNeonShift(builder, loc, vTy, extended, ops[1],
1327 /*shiftLeft=*/true);
1328 }
1329 case NEON::BI__builtin_neon_vshrn_n_v:
1330 cgf.cgm.errorNYI(expr->getSourceRange(),
1331 std::string("unimplemented AArch64 builtin call: ") +
1332 ctx.BuiltinInfo.getName(builtinID));
1333 return mlir::Value{};
1334 case NEON::BI__builtin_neon_vshr_n_v:
1335 case NEON::BI__builtin_neon_vshrq_n_v:
1336 return emitNeonRShiftImm(cgf, ops[0], ops[1], vTy, isUnsigned, loc);
1337 case NEON::BI__builtin_neon_vst1_v:
1338 case NEON::BI__builtin_neon_vst1q_v:
1339 case NEON::BI__builtin_neon_vst2_v:
1340 case NEON::BI__builtin_neon_vst2q_v:
1341 case NEON::BI__builtin_neon_vst3_v:
1342 case NEON::BI__builtin_neon_vst3q_v:
1343 case NEON::BI__builtin_neon_vst4_v:
1344 case NEON::BI__builtin_neon_vst4q_v:
1345 case NEON::BI__builtin_neon_vst2_lane_v:
1346 case NEON::BI__builtin_neon_vst2q_lane_v:
1347 case NEON::BI__builtin_neon_vst3_lane_v:
1348 case NEON::BI__builtin_neon_vst3q_lane_v:
1349 case NEON::BI__builtin_neon_vst4_lane_v:
1350 case NEON::BI__builtin_neon_vst4q_lane_v:
1351 case NEON::BI__builtin_neon_vsm3partw1q_u32:
1352 case NEON::BI__builtin_neon_vsm3partw2q_u32:
1353 case NEON::BI__builtin_neon_vsm3ss1q_u32:
1354 case NEON::BI__builtin_neon_vsm4ekeyq_u32:
1355 case NEON::BI__builtin_neon_vsm4eq_u32:
1356 case NEON::BI__builtin_neon_vsm3tt1aq_u32:
1357 case NEON::BI__builtin_neon_vsm3tt1bq_u32:
1358 case NEON::BI__builtin_neon_vsm3tt2aq_u32:
1359 case NEON::BI__builtin_neon_vsm3tt2bq_u32:
1360 cgf.cgm.errorNYI(expr->getSourceRange(),
1361 std::string("unimplemented AArch64 builtin call: ") +
1362 ctx.BuiltinInfo.getName(builtinID));
1363 return mlir::Value{};
1364 case NEON::BI__builtin_neon_vst1_x2_v:
1365 case NEON::BI__builtin_neon_vst1q_x2_v:
1366 case NEON::BI__builtin_neon_vst1_x3_v:
1367 case NEON::BI__builtin_neon_vst1q_x3_v:
1368 case NEON::BI__builtin_neon_vst1_x4_v:
1369 case NEON::BI__builtin_neon_vst1q_x4_v: {
1370 // The builtin call has the pointer first, but the AArch64 st1x2/3/4
1371 // intrinsics take the vector operands first and the pointer last.
1372 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
1373 llvm::SmallVector<mlir::Type> argTypes(ops.size() - 1, ty);
1374 argTypes.push_back(cgf.getBuilder().getVoidPtrTy());
1375 llvm::StringRef llvmIntrName = getLLVMIntrNameNoPrefix(
1376 static_cast<llvm::Intrinsic::ID>(llvmIntrinsic));
1377 return emitNeonCall(cgf.getCIRGenModule(), cgf.getBuilder(), argTypes, ops,
1378 llvmIntrName, cgf.cgm.voidTy, loc);
1379 }
1380 case NEON::BI__builtin_neon_vtrn_v:
1381 case NEON::BI__builtin_neon_vtrnq_v:
1382 case NEON::BI__builtin_neon_vtst_v:
1383 case NEON::BI__builtin_neon_vtstq_v:
1384 case NEON::BI__builtin_neon_vuzp_v:
1385 case NEON::BI__builtin_neon_vuzpq_v:
1386 case NEON::BI__builtin_neon_vxarq_u64:
1387 case NEON::BI__builtin_neon_vzip_v:
1388 case NEON::BI__builtin_neon_vzipq_v:
1389 case NEON::BI__builtin_neon_vdot_s32:
1390 case NEON::BI__builtin_neon_vdot_u32:
1391 case NEON::BI__builtin_neon_vdotq_s32:
1392 case NEON::BI__builtin_neon_vdotq_u32:
1393 case NEON::BI__builtin_neon_vfmlal_low_f16:
1394 case NEON::BI__builtin_neon_vfmlalq_low_f16:
1395 case NEON::BI__builtin_neon_vfmlsl_low_f16:
1396 case NEON::BI__builtin_neon_vfmlslq_low_f16:
1397 case NEON::BI__builtin_neon_vfmlal_high_f16:
1398 case NEON::BI__builtin_neon_vfmlalq_high_f16:
1399 case NEON::BI__builtin_neon_vfmlsl_high_f16:
1400 case NEON::BI__builtin_neon_vfmlslq_high_f16:
1401 case NEON::BI__builtin_neon_vmmlaq_s32:
1402 case NEON::BI__builtin_neon_vmmlaq_u32:
1403 cgf.cgm.errorNYI(expr->getSourceRange(),
1404 std::string("unimplemented AArch64 builtin call: ") +
1405 ctx.BuiltinInfo.getName(builtinID));
1406 return mlir::Value{};
1407 case NEON::BI__builtin_neon_vmul_v:
1408 case NEON::BI__builtin_neon_vmulq_v:
1409 return cgf.getBuilder().emitIntrinsicCallOp(loc, "aarch64.neon.pmul", vTy,
1410 ops);
1411 case NEON::BI__builtin_neon_vusmmlaq_s32:
1412 case NEON::BI__builtin_neon_vusdot_s32:
1413 case NEON::BI__builtin_neon_vusdotq_s32:
1414 case NEON::BI__builtin_neon_vbfdot_f32:
1415 case NEON::BI__builtin_neon_vbfdotq_f32:
1416 case NEON::BI__builtin_neon___a32_vcvt_bf16_f32:
1417 cgf.cgm.errorNYI(expr->getSourceRange(),
1418 std::string("unimplemented AArch64 builtin call: ") +
1419 ctx.BuiltinInfo.getName(builtinID));
1420 return mlir::Value{};
1421 }
1422
1423 // The switch stmt is intended to help catch NYI cases and will be removed
1424 // once the CIR implementation is complete. Avoid adding specialized
1425 // code in cases - that should only be required for a handful of examples.
1426 switch (builtinID) {
1427 default:
1428 cgf.cgm.errorNYI(expr->getSourceRange(),
1429 std::string("unimplemented AArch64 builtin call: ") +
1430 cgf.getContext().BuiltinInfo.getName(builtinID));
1431 break;
1432 case NEON::BI__builtin_neon_vrnd32x_f32:
1433 case NEON::BI__builtin_neon_vrnd32xq_f32:
1434 case NEON::BI__builtin_neon_vrnd32x_f64:
1435 case NEON::BI__builtin_neon_vrnd32xq_f64:
1436 case NEON::BI__builtin_neon_vrnd32z_f32:
1437 case NEON::BI__builtin_neon_vrnd32zq_f32:
1438 case NEON::BI__builtin_neon_vrnd32z_f64:
1439 case NEON::BI__builtin_neon_vrnd32zq_f64:
1440 case NEON::BI__builtin_neon_vrnd64x_f32:
1441 case NEON::BI__builtin_neon_vrnd64xq_f32:
1442 case NEON::BI__builtin_neon_vrnd64x_f64:
1443 case NEON::BI__builtin_neon_vrnd64xq_f64:
1444 case NEON::BI__builtin_neon_vrnd64z_f32:
1445 case NEON::BI__builtin_neon_vrnd64zq_f32:
1446 case NEON::BI__builtin_neon_vrnd64z_f64:
1447 case NEON::BI__builtin_neon_vrnd64zq_f64: {
1448 llvm::StringRef llvmIntrName = getLLVMIntrNameNoPrefix(
1449 static_cast<llvm::Intrinsic::ID>(llvmIntrinsic));
1450 mlir::Value result =
1451 emitNeonCall(cgf.cgm, cgf.getBuilder(), /*argTypes=*/{vTy}, ops,
1452 llvmIntrName, /*funcResTy=*/vTy, loc);
1453 mlir::Type resultType = cgf.convertType(expr->getType());
1454 return cgf.getBuilder().createBitcast(result, resultType);
1455 }
1456 case NEON::BI__builtin_neon_vhadd_v:
1457 case NEON::BI__builtin_neon_vhaddq_v:
1458 case NEON::BI__builtin_neon_vhsub_v:
1459 case NEON::BI__builtin_neon_vhsubq_v:
1460 case NEON::BI__builtin_neon_vqadd_v:
1461 case NEON::BI__builtin_neon_vqaddq_v:
1462 case NEON::BI__builtin_neon_vrhadd_v:
1463 case NEON::BI__builtin_neon_vrhaddq_v:
1464 case NEON::BI__builtin_neon_vqsub_v:
1465 case NEON::BI__builtin_neon_vqsubq_v:
1466 case NEON::BI__builtin_neon_vshl_v:
1467 case NEON::BI__builtin_neon_vshlq_v:
1468 case NEON::BI__builtin_neon_vraddhn_v:
1469 case NEON::BI__builtin_neon_vrsubhn_v:
1470 case NEON::BI__builtin_neon_vqshl_v:
1471 case NEON::BI__builtin_neon_vqshlq_v: {
1472 // Pick the signed/unsigned intrinsic when the builtin has both
1473 // (UnsignedAlts); otherwise there is a single intrinsic.
1474 unsigned intrinsic =
1475 ((modifier & UnsignedAlts) && !usgn) ? altLLVMIntrinsic : llvmIntrinsic;
1476 llvm::StringRef llvmIntrName =
1477 getLLVMIntrNameNoPrefix(static_cast<llvm::Intrinsic::ID>(intrinsic));
1478
1479 cir::VectorType argTy =
1480 deriveNeonBinaryArgType(cgf.getBuilder(), modifier, vTy);
1481
1482 mlir::Value result =
1484 /*argTypes=*/{argTy, argTy}, ops, llvmIntrName,
1485 /*funcResTy=*/vTy, loc);
1486 mlir::Type resultType = cgf.convertType(expr->getType());
1487 return cgf.getBuilder().createBitcast(result, resultType);
1488 }
1489 }
1490
1491 // NYI
1492 return nullptr;
1493}
1494
1496 unsigned builtinID, const CallExpr *expr, SmallVectorImpl<mlir::Value> &ops,
1497 SVETypeFlags typeFlags) {
1498 // Find out if any arguments are required to be integer constant expressions.
1499 unsigned iceArguments = 0;
1501 getContext().GetBuiltinType(builtinID, error, &iceArguments);
1502 assert(error == ASTContext::GE_None && "Should not codegen an error");
1503
1504 for (unsigned i = 0, e = expr->getNumArgs(); i != e; i++) {
1505 bool isIce = iceArguments & (1 << i);
1506 mlir::Value arg = emitScalarExpr(expr->getArg(i));
1507
1508 if (isIce) {
1509 cgm.errorNYI(expr->getSourceRange(),
1510 std::string("unimplemented AArch64 builtin call: ") +
1511 getContext().BuiltinInfo.getName(builtinID));
1512 }
1513
1514 // FIXME: Handle types like svint16x2_t, which are currently incorrectly
1515 // converted to i32. These should be treated as structs and unpacked.
1516
1517 ops.push_back(arg);
1518 }
1519 return true;
1520}
1521
1522// Reinterpret the input predicate so that it can be used to correctly isolate
1523// the elements of the specified datatype.
1524mlir::Value CIRGenFunction::emitSVEPredicateCast(mlir::Value pred,
1525 unsigned minNumElts,
1526 mlir::Location loc) {
1527
1528 // TODO: Handle "aarch64.svcount" once we get round to supporting SME.
1529
1530 auto retTy = cir::VectorType::get(builder.getUIntNTy(1), minNumElts,
1531 /*is_scalable=*/true);
1532 if (pred.getType() == retTy)
1533 return pred;
1534
1535 llvm::Intrinsic::ID intID;
1536 switch (minNumElts) {
1537 default:
1538 llvm_unreachable("unsupported element count!");
1539 case 1:
1540 case 2:
1541 case 4:
1542 case 8:
1543 intID = Intrinsic::aarch64_sve_convert_from_svbool;
1544 break;
1545 case 16:
1546 intID = Intrinsic::aarch64_sve_convert_to_svbool;
1547 break;
1548 }
1549
1550 llvm::StringRef llvmIntrName = getLLVMIntrNameNoPrefix(intID);
1551 auto call = builder.emitIntrinsicCallOp(loc, llvmIntrName, retTy,
1552 mlir::ValueRange{pred});
1553 assert(call.getType() == retTy && "Unexpected return type!");
1554 return call;
1555}
1556
1557//===----------------------------------------------------------------------===//
1558// SVE helpers
1559//===----------------------------------------------------------------------===//
1560// Get the minimum number of elements in an SVE vector for the given element
1561// type. The actual number of elements in the vector would be an integer (power
1562// of two) multiple of this value.
1564 switch (sveType) {
1565 default:
1566 llvm_unreachable("Invalid SVETypeFlag!");
1567
1568 case SVETypeFlags::EltTyInt8:
1569 return 16;
1570 case SVETypeFlags::EltTyInt16:
1571 return 8;
1572 case SVETypeFlags::EltTyInt32:
1573 return 4;
1574 case SVETypeFlags::EltTyInt64:
1575 return 2;
1576
1577 case SVETypeFlags::EltTyMFloat8:
1578 return 16;
1579 case SVETypeFlags::EltTyFloat16:
1580 case SVETypeFlags::EltTyBFloat16:
1581 return 8;
1582 case SVETypeFlags::EltTyFloat32:
1583 return 4;
1584 case SVETypeFlags::EltTyFloat64:
1585 return 2;
1586
1587 case SVETypeFlags::EltTyBool8:
1588 return 16;
1589 case SVETypeFlags::EltTyBool16:
1590 return 8;
1591 case SVETypeFlags::EltTyBool32:
1592 return 4;
1593 case SVETypeFlags::EltTyBool64:
1594 return 2;
1595 }
1596}
1597
1598cir::VectorType CIRGenFunction::getSVEType(const SVETypeFlags &typeFlags) {
1599 switch (typeFlags.getEltType()) {
1600 default:
1601 llvm_unreachable("Invalid SVETypeFlag!");
1602
1603 case SVETypeFlags::EltTyInt8:
1604 return cir::VectorType::get(builder.getUInt8Ty(), 16, true);
1605 case SVETypeFlags::EltTyInt16:
1606 return cir::VectorType::get(builder.getUInt16Ty(), 8, true);
1607 case SVETypeFlags::EltTyInt32:
1608 return cir::VectorType::get(builder.getUInt32Ty(), 4, true);
1609 case SVETypeFlags::EltTyInt64:
1610 return cir::VectorType::get(builder.getUInt64Ty(), 2, true);
1611
1612 case SVETypeFlags::EltTyMFloat8:
1613 return cir::VectorType::get(builder.getUInt8Ty(), 16, true);
1614 case SVETypeFlags::EltTyFloat16:
1615 return cir::VectorType::get(builder.getFp16Ty(), 8, true);
1616 case SVETypeFlags::EltTyBFloat16:
1617 return cir::VectorType::get(builder.getBF16Type(), 8, true);
1618 case SVETypeFlags::EltTyFloat32:
1619 return cir::VectorType::get(builder.getF32Type(), 4, true);
1620 case SVETypeFlags::EltTyFloat64:
1621 return cir::VectorType::get(builder.getDoubleTy(), 2, true);
1622
1623 case SVETypeFlags::EltTyBool8:
1624 return cir::VectorType::get(builder.getUIntNTy(1), 16, true);
1625 case SVETypeFlags::EltTyBool16:
1626 return cir::VectorType::get(builder.getUIntNTy(1), 8, true);
1627 case SVETypeFlags::EltTyBool32:
1628 return cir::VectorType::get(builder.getUIntNTy(1), 4, true);
1629 case SVETypeFlags::EltTyBool64:
1630 return cir::VectorType::get(builder.getUIntNTy(1), 2, true);
1631 }
1632}
1633
1634// TODO(cir): Share with OGCG
1635constexpr unsigned sveBitsPerBlock = 128;
1636
1637static cir::VectorType getSVEVectorForElementType(CIRGenModule &cgm,
1638 mlir::Type eltTy) {
1639 unsigned numElts =
1641 return cir::VectorType::get(eltTy, numElts, /*is_scalable=*/true);
1642}
1643
1644//===----------------------------------------------------------------------===//
1645// SVE helpers
1646//===----------------------------------------------------------------------===//
1647std::optional<mlir::Value>
1649 const CallExpr *expr) {
1650 mlir::Type ty = convertType(expr->getType());
1651
1652 if (builtinID >= SVE::BI__builtin_sve_reinterpret_s8_s8 &&
1653 builtinID <= SVE::BI__builtin_sve_reinterpret_f64_f64_x4) {
1654 cgm.errorNYI(expr->getSourceRange(),
1655 std::string("unimplemented AArch64 builtin call: ") +
1656 getContext().BuiltinInfo.getName(builtinID));
1657 return mlir::Value{};
1658 }
1659
1661
1662 auto *builtinIntrInfo =
1665
1666 // The operands of the builtin call
1668
1669 SVETypeFlags typeFlags(builtinIntrInfo->TypeModifier);
1671 typeFlags))
1672 return mlir::Value{};
1673
1674 if (typeFlags.isLoad() || typeFlags.isStore() || typeFlags.isGatherLoad() ||
1675 typeFlags.isScatterStore() || typeFlags.isPrefetch() ||
1676 typeFlags.isGatherPrefetch() || typeFlags.isStructLoad() ||
1677 typeFlags.isStructStore() || typeFlags.isTupleSet() ||
1678 typeFlags.isTupleGet() || typeFlags.isTupleCreate() ||
1679 typeFlags.isUndef())
1680 cgm.errorNYI(expr->getSourceRange(),
1681 std::string("unimplemented AArch64 builtin call: ") +
1682 getContext().BuiltinInfo.getName(builtinID));
1683
1684 mlir::Location loc = getLoc(expr->getExprLoc());
1685
1686 // Handle built-ins for which there is a corresponding LLVM Intrinsic.
1687 // -------------------------------------------------------------------
1688 if (builtinIntrInfo->LLVMIntrinsic != 0) {
1689 // Emit set FPMR for intrinsics that require it.
1690 if (typeFlags.setsFPMR())
1691 cgm.errorNYI(expr->getSourceRange(),
1692 std::string("unimplemented AArch64 builtin call: ") +
1693 getContext().BuiltinInfo.getName(builtinID));
1694
1695 // Zero-ing predication
1696 if (typeFlags.getMergeType() == SVETypeFlags::MergeZeroExp) {
1697 auto null = builder.getNullValue(convertType(expr->getType()),
1698 getLoc(expr->getExprLoc()));
1699 ops.insert(ops.begin(), null);
1700 }
1701
1702 if (typeFlags.getMergeType() == SVETypeFlags::MergeAnyExp)
1703 ops.insert(ops.begin(),
1704 builder.getConstant(loc, cir::UndefAttr::get(ty)));
1705
1706 // Some ACLE builtins leave out the argument to specify the predicate
1707 // pattern, which is expected to be expanded to an SV_ALL pattern.
1708 if (typeFlags.isAppendSVALL())
1709 cgm.errorNYI(expr->getSourceRange(),
1710 std::string("unimplemented AArch64 builtin call: ") +
1711 getContext().BuiltinInfo.getName(builtinID));
1712 if (typeFlags.isInsertOp1SVALL())
1713 cgm.errorNYI(expr->getSourceRange(),
1714 std::string("unimplemented AArch64 builtin call: ") +
1715 getContext().BuiltinInfo.getName(builtinID));
1716
1717 // Predicates must match the main datatype.
1718 for (mlir::Value &op : ops)
1719 if (auto predTy = dyn_cast<cir::VectorType>(op.getType()))
1720 if (auto cirInt = dyn_cast<cir::IntType>(predTy.getElementType()))
1721 if (cirInt.getWidth() == 1)
1723 op, getSVEMinEltCount(typeFlags.getEltType()), loc);
1724
1725 // Splat scalar operand to vector (intrinsics with _n infix)
1726 if (typeFlags.hasSplatOperand()) {
1727 unsigned opNo = typeFlags.getSplatOperand();
1728 ops[opNo] = cir::VecSplatOp::create(
1729 builder, loc, getSVEVectorForElementType(cgm, ops[opNo].getType()),
1730 ops[opNo]);
1731 }
1732
1733 if (typeFlags.isReverseCompare())
1734 cgm.errorNYI(expr->getSourceRange(),
1735 std::string("unimplemented AArch64 builtin call: ") +
1736 getContext().BuiltinInfo.getName(builtinID));
1737 if (typeFlags.isReverseUSDOT())
1738 cgm.errorNYI(expr->getSourceRange(),
1739 std::string("unimplemented AArch64 builtin call: ") +
1740 getContext().BuiltinInfo.getName(builtinID));
1741 if (typeFlags.isReverseMergeAnyBinOp() &&
1742 typeFlags.getMergeType() == SVETypeFlags::MergeAny)
1743 cgm.errorNYI(expr->getSourceRange(),
1744 std::string("unimplemented AArch64 builtin call: ") +
1745 getContext().BuiltinInfo.getName(builtinID));
1746 if (typeFlags.isReverseMergeAnyAccOp() &&
1747 typeFlags.getMergeType() == SVETypeFlags::MergeAny)
1748 cgm.errorNYI(expr->getSourceRange(),
1749 std::string("unimplemented AArch64 builtin call: ") +
1750 getContext().BuiltinInfo.getName(builtinID));
1751
1752 // Predicated intrinsics with _z suffix.
1753 if (typeFlags.getMergeType() == SVETypeFlags::MergeZero) {
1754 cgm.errorNYI(expr->getSourceRange(),
1755 std::string("unimplemented AArch64 builtin call: ") +
1756 getContext().BuiltinInfo.getName(builtinID));
1757 }
1758
1759 llvm::StringRef llvmIntrName = getLLVMIntrNameNoPrefix(
1760 static_cast<llvm::Intrinsic::ID>(builtinIntrInfo->LLVMIntrinsic));
1761 auto retTy = convertType(expr->getType());
1762
1763 auto call = builder.emitIntrinsicCallOp(loc, llvmIntrName, retTy,
1764 mlir::ValueRange{ops});
1765 if (call.getType() == retTy)
1766 return call;
1767
1768 // Predicate results must be converted to svbool_t.
1769 if (isa<mlir::VectorType>(retTy) &&
1770 cast<mlir::VectorType>(retTy).isScalable())
1771 cgm.errorNYI(expr->getSourceRange(),
1772 std::string("unimplemented AArch64 builtin call: ") +
1773 getContext().BuiltinInfo.getName(builtinID));
1774 // TODO Handle struct types, e.g. svint8x2_t (update the converter first).
1775
1776 llvm_unreachable("unsupported element count!");
1777 }
1778
1779 // Handle the remaining built-ins.
1780 // -------------------------------
1781 switch (builtinID) {
1782 default:
1783 return std::nullopt;
1784
1785 case SVE::BI__builtin_sve_svreinterpret_b:
1786 case SVE::BI__builtin_sve_svreinterpret_c:
1787 case SVE::BI__builtin_sve_svpsel_lane_b8:
1788 case SVE::BI__builtin_sve_svpsel_lane_b16:
1789 case SVE::BI__builtin_sve_svpsel_lane_b32:
1790 case SVE::BI__builtin_sve_svpsel_lane_b64:
1791 case SVE::BI__builtin_sve_svpsel_lane_c8:
1792 case SVE::BI__builtin_sve_svpsel_lane_c16:
1793 case SVE::BI__builtin_sve_svpsel_lane_c32:
1794 case SVE::BI__builtin_sve_svpsel_lane_c64:
1795 case SVE::BI__builtin_sve_svmov_b_z:
1796 case SVE::BI__builtin_sve_svnot_b_z:
1797 case SVE::BI__builtin_sve_svmovlb_u16:
1798 case SVE::BI__builtin_sve_svmovlb_u32:
1799 case SVE::BI__builtin_sve_svmovlb_u64:
1800 case SVE::BI__builtin_sve_svmovlb_s16:
1801 case SVE::BI__builtin_sve_svmovlb_s32:
1802 case SVE::BI__builtin_sve_svmovlb_s64:
1803 case SVE::BI__builtin_sve_svmovlt_u16:
1804 case SVE::BI__builtin_sve_svmovlt_u32:
1805 case SVE::BI__builtin_sve_svmovlt_u64:
1806 case SVE::BI__builtin_sve_svmovlt_s16:
1807 case SVE::BI__builtin_sve_svmovlt_s32:
1808 case SVE::BI__builtin_sve_svmovlt_s64:
1809 case SVE::BI__builtin_sve_svpmullt_u16:
1810 case SVE::BI__builtin_sve_svpmullt_u64:
1811 case SVE::BI__builtin_sve_svpmullt_n_u16:
1812 case SVE::BI__builtin_sve_svpmullt_n_u64:
1813 case SVE::BI__builtin_sve_svpmullb_u16:
1814 case SVE::BI__builtin_sve_svpmullb_u64:
1815 case SVE::BI__builtin_sve_svpmullb_n_u16:
1816 case SVE::BI__builtin_sve_svpmullb_n_u64:
1817 cgm.errorNYI(expr->getSourceRange(),
1818 std::string("unimplemented AArch64 builtin call: ") +
1819 getContext().BuiltinInfo.getName(builtinID));
1820 return mlir::Value{};
1821
1822 case SVE::BI__builtin_sve_svdup_n_b8:
1823 case SVE::BI__builtin_sve_svdup_n_b16:
1824 case SVE::BI__builtin_sve_svdup_n_b32:
1825 case SVE::BI__builtin_sve_svdup_n_b64: {
1826 // Cast from cir.bool (input type) to cir.int<u, 1> (element type of the
1827 // result vector).
1828 auto dup = builder.createBitcast(ops[0], builder.getUIntNTy(1));
1829
1830 // Splat
1831 dup = cir::VecSplatOp::create(builder, loc, getSVEType(typeFlags), dup);
1832
1833 // Cast to svbool_t, i.e. <vscale x 16 x i1>. The actual result could be
1834 // e.g. <vscale x 8 x i1> (for b16), but only svbool_t (i.e. full
1835 // predicate register) is "storable" (as per SVE ABI).
1836 return builtinID == SVE::BI__builtin_sve_svdup_n_b8
1837 ? dup
1838 : emitSVEPredicateCast(dup, 16, loc);
1839 }
1840
1841 case SVE::BI__builtin_sve_svdupq_n_b8:
1842 case SVE::BI__builtin_sve_svdupq_n_b16:
1843 case SVE::BI__builtin_sve_svdupq_n_b32:
1844 case SVE::BI__builtin_sve_svdupq_n_b64:
1845 case SVE::BI__builtin_sve_svdupq_n_u8:
1846 case SVE::BI__builtin_sve_svdupq_n_s8:
1847 case SVE::BI__builtin_sve_svdupq_n_u64:
1848 case SVE::BI__builtin_sve_svdupq_n_f64:
1849 case SVE::BI__builtin_sve_svdupq_n_s64:
1850 case SVE::BI__builtin_sve_svdupq_n_u16:
1851 case SVE::BI__builtin_sve_svdupq_n_f16:
1852 case SVE::BI__builtin_sve_svdupq_n_bf16:
1853 case SVE::BI__builtin_sve_svdupq_n_s16:
1854 case SVE::BI__builtin_sve_svdupq_n_u32:
1855 case SVE::BI__builtin_sve_svdupq_n_f32:
1856 case SVE::BI__builtin_sve_svdupq_n_s32:
1857 case SVE::BI__builtin_sve_svpfalse_b:
1858 case SVE::BI__builtin_sve_svpfalse_c:
1859 cgm.errorNYI(expr->getSourceRange(),
1860 std::string("unimplemented AArch64 builtin call: ") +
1861 getContext().BuiltinInfo.getName(builtinID));
1862 return mlir::Value{};
1863
1864 case SVE::BI__builtin_sve_svlen_u8:
1865 case SVE::BI__builtin_sve_svlen_s8:
1866 return genVscaleTimesFactor(loc, builder, convertType(expr->getType()), 16);
1867
1868 case SVE::BI__builtin_sve_svlen_u16:
1869 case SVE::BI__builtin_sve_svlen_s16:
1870 case SVE::BI__builtin_sve_svlen_f16:
1871 case SVE::BI__builtin_sve_svlen_bf16:
1872 return genVscaleTimesFactor(loc, builder, convertType(expr->getType()), 8);
1873
1874 case SVE::BI__builtin_sve_svlen_u32:
1875 case SVE::BI__builtin_sve_svlen_s32:
1876 case SVE::BI__builtin_sve_svlen_f32:
1877 return genVscaleTimesFactor(loc, builder, convertType(expr->getType()), 4);
1878
1879 case SVE::BI__builtin_sve_svlen_u64:
1880 case SVE::BI__builtin_sve_svlen_s64:
1881 case SVE::BI__builtin_sve_svlen_f64:
1882 return genVscaleTimesFactor(loc, builder, convertType(expr->getType()), 2);
1883
1884 case SVE::BI__builtin_sve_svtbl2_u8:
1885 case SVE::BI__builtin_sve_svtbl2_s8:
1886 case SVE::BI__builtin_sve_svtbl2_u16:
1887 case SVE::BI__builtin_sve_svtbl2_s16:
1888 case SVE::BI__builtin_sve_svtbl2_u32:
1889 case SVE::BI__builtin_sve_svtbl2_s32:
1890 case SVE::BI__builtin_sve_svtbl2_u64:
1891 case SVE::BI__builtin_sve_svtbl2_s64:
1892 case SVE::BI__builtin_sve_svtbl2_f16:
1893 case SVE::BI__builtin_sve_svtbl2_bf16:
1894 case SVE::BI__builtin_sve_svtbl2_f32:
1895 case SVE::BI__builtin_sve_svtbl2_f64:
1896 case SVE::BI__builtin_sve_svset_neonq_s8:
1897 case SVE::BI__builtin_sve_svset_neonq_s16:
1898 case SVE::BI__builtin_sve_svset_neonq_s32:
1899 case SVE::BI__builtin_sve_svset_neonq_s64:
1900 case SVE::BI__builtin_sve_svset_neonq_u8:
1901 case SVE::BI__builtin_sve_svset_neonq_u16:
1902 case SVE::BI__builtin_sve_svset_neonq_u32:
1903 case SVE::BI__builtin_sve_svset_neonq_u64:
1904 case SVE::BI__builtin_sve_svset_neonq_f16:
1905 case SVE::BI__builtin_sve_svset_neonq_f32:
1906 case SVE::BI__builtin_sve_svset_neonq_f64:
1907 case SVE::BI__builtin_sve_svset_neonq_bf16:
1908 case SVE::BI__builtin_sve_svset_neonq_mf8:
1909 case SVE::BI__builtin_sve_svget_neonq_s8:
1910 case SVE::BI__builtin_sve_svget_neonq_s16:
1911 case SVE::BI__builtin_sve_svget_neonq_s32:
1912 case SVE::BI__builtin_sve_svget_neonq_s64:
1913 case SVE::BI__builtin_sve_svget_neonq_u8:
1914 case SVE::BI__builtin_sve_svget_neonq_u16:
1915 case SVE::BI__builtin_sve_svget_neonq_u32:
1916 case SVE::BI__builtin_sve_svget_neonq_u64:
1917 case SVE::BI__builtin_sve_svget_neonq_f16:
1918 case SVE::BI__builtin_sve_svget_neonq_f32:
1919 case SVE::BI__builtin_sve_svget_neonq_f64:
1920 case SVE::BI__builtin_sve_svget_neonq_bf16:
1921 case SVE::BI__builtin_sve_svget_neonq_mf8:
1922 case SVE::BI__builtin_sve_svdup_neonq_s8:
1923 case SVE::BI__builtin_sve_svdup_neonq_s16:
1924 case SVE::BI__builtin_sve_svdup_neonq_s32:
1925 case SVE::BI__builtin_sve_svdup_neonq_s64:
1926 case SVE::BI__builtin_sve_svdup_neonq_u8:
1927 case SVE::BI__builtin_sve_svdup_neonq_u16:
1928 case SVE::BI__builtin_sve_svdup_neonq_u32:
1929 case SVE::BI__builtin_sve_svdup_neonq_u64:
1930 case SVE::BI__builtin_sve_svdup_neonq_f16:
1931 case SVE::BI__builtin_sve_svdup_neonq_f32:
1932 case SVE::BI__builtin_sve_svdup_neonq_f64:
1933 case SVE::BI__builtin_sve_svdup_neonq_bf16:
1934 case SVE::BI__builtin_sve_svdup_neonq_mf8:
1935 cgm.errorNYI(expr->getSourceRange(),
1936 std::string("unimplemented AArch64 builtin call: ") +
1937 getContext().BuiltinInfo.getName(builtinID));
1938 return mlir::Value{};
1939 }
1940
1941 // Unreachable: All cases in the switch above return.
1942}
1943
1944std::optional<mlir::Value>
1946 const CallExpr *expr) {
1948
1949 cgm.errorNYI(expr->getSourceRange(),
1950 std::string("unimplemented AArch64 builtin call: ") +
1951 getContext().BuiltinInfo.getName(builtinID));
1952 return mlir::Value{};
1953}
1954
1955// Some intrinsics are equivalent for codegen.
1956static const std::pair<unsigned, unsigned> neonEquivalentIntrinsicMap[] = {
1957 {
1958 NEON::BI__builtin_neon_vabd_f16,
1959 NEON::BI__builtin_neon_vabd_v,
1960 },
1961 {
1962 NEON::BI__builtin_neon_vabdq_f16,
1963 NEON::BI__builtin_neon_vabdq_v,
1964 },
1965 {
1966 NEON::BI__builtin_neon_vabs_f16,
1967 NEON::BI__builtin_neon_vabs_v,
1968 },
1969 {
1970 NEON::BI__builtin_neon_vabsq_f16,
1971 NEON::BI__builtin_neon_vabsq_v,
1972 },
1973 {
1974 NEON::BI__builtin_neon_vcage_f16,
1975 NEON::BI__builtin_neon_vcage_v,
1976 },
1977 {
1978 NEON::BI__builtin_neon_vcageq_f16,
1979 NEON::BI__builtin_neon_vcageq_v,
1980 },
1981 {
1982 NEON::BI__builtin_neon_vcagt_f16,
1983 NEON::BI__builtin_neon_vcagt_v,
1984 },
1985 {
1986 NEON::BI__builtin_neon_vcagtq_f16,
1987 NEON::BI__builtin_neon_vcagtq_v,
1988 },
1989 {
1990 NEON::BI__builtin_neon_vcale_f16,
1991 NEON::BI__builtin_neon_vcale_v,
1992 },
1993 {
1994 NEON::BI__builtin_neon_vcaleq_f16,
1995 NEON::BI__builtin_neon_vcaleq_v,
1996 },
1997 {
1998 NEON::BI__builtin_neon_vcalt_f16,
1999 NEON::BI__builtin_neon_vcalt_v,
2000 },
2001 {
2002 NEON::BI__builtin_neon_vcaltq_f16,
2003 NEON::BI__builtin_neon_vcaltq_v,
2004 },
2005 {
2006 NEON::BI__builtin_neon_vceqz_f16,
2007 NEON::BI__builtin_neon_vceqz_v,
2008 },
2009 {
2010 NEON::BI__builtin_neon_vceqzq_f16,
2011 NEON::BI__builtin_neon_vceqzq_v,
2012 },
2013 {
2014 NEON::BI__builtin_neon_vcgez_f16,
2015 NEON::BI__builtin_neon_vcgez_v,
2016 },
2017 {
2018 NEON::BI__builtin_neon_vcgezq_f16,
2019 NEON::BI__builtin_neon_vcgezq_v,
2020 },
2021 {
2022 NEON::BI__builtin_neon_vcgtz_f16,
2023 NEON::BI__builtin_neon_vcgtz_v,
2024 },
2025 {
2026 NEON::BI__builtin_neon_vcgtzq_f16,
2027 NEON::BI__builtin_neon_vcgtzq_v,
2028 },
2029 {
2030 NEON::BI__builtin_neon_vclez_f16,
2031 NEON::BI__builtin_neon_vclez_v,
2032 },
2033 {
2034 NEON::BI__builtin_neon_vclezq_f16,
2035 NEON::BI__builtin_neon_vclezq_v,
2036 },
2037 {
2038 NEON::BI__builtin_neon_vcltz_f16,
2039 NEON::BI__builtin_neon_vcltz_v,
2040 },
2041 {
2042 NEON::BI__builtin_neon_vcltzq_f16,
2043 NEON::BI__builtin_neon_vcltzq_v,
2044 },
2045 {
2046 NEON::BI__builtin_neon_vfma_f16,
2047 NEON::BI__builtin_neon_vfma_v,
2048 },
2049 {
2050 NEON::BI__builtin_neon_vfma_lane_f16,
2051 NEON::BI__builtin_neon_vfma_lane_v,
2052 },
2053 {
2054 NEON::BI__builtin_neon_vfma_laneq_f16,
2055 NEON::BI__builtin_neon_vfma_laneq_v,
2056 },
2057 {
2058 NEON::BI__builtin_neon_vfmaq_f16,
2059 NEON::BI__builtin_neon_vfmaq_v,
2060 },
2061 {
2062 NEON::BI__builtin_neon_vfmaq_lane_f16,
2063 NEON::BI__builtin_neon_vfmaq_lane_v,
2064 },
2065 {
2066 NEON::BI__builtin_neon_vfmaq_laneq_f16,
2067 NEON::BI__builtin_neon_vfmaq_laneq_v,
2068 },
2069 {
2070 NEON::BI__builtin_neon_vmax_f16,
2071 NEON::BI__builtin_neon_vmax_v,
2072 },
2073 {
2074 NEON::BI__builtin_neon_vmaxnm_f16,
2075 NEON::BI__builtin_neon_vmaxnm_v,
2076 },
2077 {
2078 NEON::BI__builtin_neon_vmaxnmq_f16,
2079 NEON::BI__builtin_neon_vmaxnmq_v,
2080 },
2081 {
2082 NEON::BI__builtin_neon_vmaxq_f16,
2083 NEON::BI__builtin_neon_vmaxq_v,
2084 },
2085 {
2086 NEON::BI__builtin_neon_vmin_f16,
2087 NEON::BI__builtin_neon_vmin_v,
2088 },
2089 {
2090 NEON::BI__builtin_neon_vminnm_f16,
2091 NEON::BI__builtin_neon_vminnm_v,
2092 },
2093 {
2094 NEON::BI__builtin_neon_vminnmq_f16,
2095 NEON::BI__builtin_neon_vminnmq_v,
2096 },
2097 {
2098 NEON::BI__builtin_neon_vminq_f16,
2099 NEON::BI__builtin_neon_vminq_v,
2100 },
2101 {
2102 NEON::BI__builtin_neon_vmulx_f16,
2103 NEON::BI__builtin_neon_vmulx_v,
2104 },
2105 {
2106 NEON::BI__builtin_neon_vmulxq_f16,
2107 NEON::BI__builtin_neon_vmulxq_v,
2108 },
2109 {
2110 NEON::BI__builtin_neon_vpadd_f16,
2111 NEON::BI__builtin_neon_vpadd_v,
2112 },
2113 {
2114 NEON::BI__builtin_neon_vpaddq_f16,
2115 NEON::BI__builtin_neon_vpaddq_v,
2116 },
2117 {
2118 NEON::BI__builtin_neon_vpmax_f16,
2119 NEON::BI__builtin_neon_vpmax_v,
2120 },
2121 {
2122 NEON::BI__builtin_neon_vpmaxnm_f16,
2123 NEON::BI__builtin_neon_vpmaxnm_v,
2124 },
2125 {
2126 NEON::BI__builtin_neon_vpmaxnmq_f16,
2127 NEON::BI__builtin_neon_vpmaxnmq_v,
2128 },
2129 {
2130 NEON::BI__builtin_neon_vpmaxq_f16,
2131 NEON::BI__builtin_neon_vpmaxq_v,
2132 },
2133 {
2134 NEON::BI__builtin_neon_vpmin_f16,
2135 NEON::BI__builtin_neon_vpmin_v,
2136 },
2137 {
2138 NEON::BI__builtin_neon_vpminnm_f16,
2139 NEON::BI__builtin_neon_vpminnm_v,
2140 },
2141 {
2142 NEON::BI__builtin_neon_vpminnmq_f16,
2143 NEON::BI__builtin_neon_vpminnmq_v,
2144 },
2145 {
2146 NEON::BI__builtin_neon_vpminq_f16,
2147 NEON::BI__builtin_neon_vpminq_v,
2148 },
2149 {
2150 NEON::BI__builtin_neon_vrecpe_f16,
2151 NEON::BI__builtin_neon_vrecpe_v,
2152 },
2153 {
2154 NEON::BI__builtin_neon_vrecpeq_f16,
2155 NEON::BI__builtin_neon_vrecpeq_v,
2156 },
2157 {
2158 NEON::BI__builtin_neon_vrecps_f16,
2159 NEON::BI__builtin_neon_vrecps_v,
2160 },
2161 {
2162 NEON::BI__builtin_neon_vrecpsq_f16,
2163 NEON::BI__builtin_neon_vrecpsq_v,
2164 },
2165 {
2166 NEON::BI__builtin_neon_vrnd_f16,
2167 NEON::BI__builtin_neon_vrnd_v,
2168 },
2169 {
2170 NEON::BI__builtin_neon_vrnda_f16,
2171 NEON::BI__builtin_neon_vrnda_v,
2172 },
2173 {
2174 NEON::BI__builtin_neon_vrndaq_f16,
2175 NEON::BI__builtin_neon_vrndaq_v,
2176 },
2177 {
2178 NEON::BI__builtin_neon_vrndi_f16,
2179 NEON::BI__builtin_neon_vrndi_v,
2180 },
2181 {
2182 NEON::BI__builtin_neon_vrndiq_f16,
2183 NEON::BI__builtin_neon_vrndiq_v,
2184 },
2185 {
2186 NEON::BI__builtin_neon_vrndm_f16,
2187 NEON::BI__builtin_neon_vrndm_v,
2188 },
2189 {
2190 NEON::BI__builtin_neon_vrndmq_f16,
2191 NEON::BI__builtin_neon_vrndmq_v,
2192 },
2193 {
2194 NEON::BI__builtin_neon_vrndn_f16,
2195 NEON::BI__builtin_neon_vrndn_v,
2196 },
2197 {
2198 NEON::BI__builtin_neon_vrndnq_f16,
2199 NEON::BI__builtin_neon_vrndnq_v,
2200 },
2201 {
2202 NEON::BI__builtin_neon_vrndp_f16,
2203 NEON::BI__builtin_neon_vrndp_v,
2204 },
2205 {
2206 NEON::BI__builtin_neon_vrndpq_f16,
2207 NEON::BI__builtin_neon_vrndpq_v,
2208 },
2209 {
2210 NEON::BI__builtin_neon_vrndq_f16,
2211 NEON::BI__builtin_neon_vrndq_v,
2212 },
2213 {
2214 NEON::BI__builtin_neon_vrndx_f16,
2215 NEON::BI__builtin_neon_vrndx_v,
2216 },
2217 {
2218 NEON::BI__builtin_neon_vrndxq_f16,
2219 NEON::BI__builtin_neon_vrndxq_v,
2220 },
2221 {
2222 NEON::BI__builtin_neon_vrsqrte_f16,
2223 NEON::BI__builtin_neon_vrsqrte_v,
2224 },
2225 {
2226 NEON::BI__builtin_neon_vrsqrteq_f16,
2227 NEON::BI__builtin_neon_vrsqrteq_v,
2228 },
2229 {
2230 NEON::BI__builtin_neon_vrsqrts_f16,
2231 NEON::BI__builtin_neon_vrsqrts_v,
2232 },
2233 {
2234 NEON::BI__builtin_neon_vrsqrtsq_f16,
2235 NEON::BI__builtin_neon_vrsqrtsq_v,
2236 },
2237 {
2238 NEON::BI__builtin_neon_vsqrt_f16,
2239 NEON::BI__builtin_neon_vsqrt_v,
2240 },
2241 {
2242 NEON::BI__builtin_neon_vsqrtq_f16,
2243 NEON::BI__builtin_neon_vsqrtq_v,
2244 },
2245 // The mangling rules cause us to have one ID for each type for
2246 // vldap1(q)_lane and vstl1(q)_lane, but codegen is equivalent for all of
2247 // them. Choose an arbitrary one to be handled as tha canonical variation.
2248 {NEON::BI__builtin_neon_vldap1_lane_u64,
2249 NEON::BI__builtin_neon_vldap1_lane_s64},
2250 {NEON::BI__builtin_neon_vldap1_lane_f64,
2251 NEON::BI__builtin_neon_vldap1_lane_s64},
2252 {NEON::BI__builtin_neon_vldap1_lane_p64,
2253 NEON::BI__builtin_neon_vldap1_lane_s64},
2254 {NEON::BI__builtin_neon_vldap1q_lane_u64,
2255 NEON::BI__builtin_neon_vldap1q_lane_s64},
2256 {NEON::BI__builtin_neon_vldap1q_lane_f64,
2257 NEON::BI__builtin_neon_vldap1q_lane_s64},
2258 {NEON::BI__builtin_neon_vldap1q_lane_p64,
2259 NEON::BI__builtin_neon_vldap1q_lane_s64},
2260 {NEON::BI__builtin_neon_vstl1_lane_u64,
2261 NEON::BI__builtin_neon_vstl1_lane_s64},
2262 {NEON::BI__builtin_neon_vstl1_lane_f64,
2263 NEON::BI__builtin_neon_vstl1_lane_s64},
2264 {NEON::BI__builtin_neon_vstl1_lane_p64,
2265 NEON::BI__builtin_neon_vstl1_lane_s64},
2266 {NEON::BI__builtin_neon_vstl1q_lane_u64,
2267 NEON::BI__builtin_neon_vstl1q_lane_s64},
2268 {NEON::BI__builtin_neon_vstl1q_lane_f64,
2269 NEON::BI__builtin_neon_vstl1q_lane_s64},
2270 {NEON::BI__builtin_neon_vstl1q_lane_p64,
2271 NEON::BI__builtin_neon_vstl1q_lane_s64},
2272};
2273
2274std::optional<mlir::Value>
2277 llvm::Triple::ArchType arch) {
2278 if (builtinID >= clang::AArch64::FirstSVEBuiltin &&
2279 builtinID <= clang::AArch64::LastSVEBuiltin)
2280 return emitAArch64SVEBuiltinExpr(builtinID, expr);
2281
2282 if (builtinID >= clang::AArch64::FirstSMEBuiltin &&
2283 builtinID <= clang::AArch64::LastSMEBuiltin)
2284 return emitAArch64SMEBuiltinExpr(builtinID, expr);
2285
2286 if (builtinID == Builtin::BI__builtin_cpu_supports) {
2287 cgm.errorNYI(expr->getSourceRange(),
2288 std::string("unimplemented AArch64 builtin call: ") +
2289 getContext().BuiltinInfo.getName(builtinID));
2290 return mlir::Value{};
2291 }
2292
2293 switch (builtinID) {
2294 default:
2295 break;
2296 case clang::AArch64::BI__builtin_arm_nop:
2297 case clang::AArch64::BI__builtin_arm_yield:
2298 case clang::AArch64::BI__yield:
2299 case clang::AArch64::BI__builtin_arm_wfe:
2300 case clang::AArch64::BI__wfe:
2301 case clang::AArch64::BI__builtin_arm_wfi:
2302 case clang::AArch64::BI__wfi:
2303 case clang::AArch64::BI__builtin_arm_sev:
2304 case clang::AArch64::BI__sev:
2305 case clang::AArch64::BI__builtin_arm_sevl:
2306 case clang::AArch64::BI__sevl:
2307 cgm.errorNYI(expr->getSourceRange(),
2308 std::string("unimplemented AArch64 builtin call: ") +
2309 getContext().BuiltinInfo.getName(builtinID));
2310 return mlir::Value{};
2311 }
2312
2313 if (builtinID == clang::AArch64::BI__builtin_arm_trap) {
2314 cgm.errorNYI(expr->getSourceRange(),
2315 std::string("unimplemented AArch64 builtin call: ") +
2316 getContext().BuiltinInfo.getName(builtinID));
2317 return mlir::Value{};
2318 }
2319
2320 if (builtinID == clang::AArch64::BI__builtin_arm_get_sme_state) {
2321 cgm.errorNYI(expr->getSourceRange(),
2322 std::string("unimplemented AArch64 builtin call: ") +
2323 getContext().BuiltinInfo.getName(builtinID));
2324 return mlir::Value{};
2325 }
2326
2327 if (builtinID == clang::AArch64::BI__builtin_arm_rbit) {
2328 cgm.errorNYI(expr->getSourceRange(),
2329 std::string("unimplemented AArch64 builtin call: ") +
2330 getContext().BuiltinInfo.getName(builtinID));
2331 return mlir::Value{};
2332 }
2333 if (builtinID == clang::AArch64::BI__builtin_arm_rbit64) {
2334 cgm.errorNYI(expr->getSourceRange(),
2335 std::string("unimplemented AArch64 builtin call: ") +
2336 getContext().BuiltinInfo.getName(builtinID));
2337 return mlir::Value{};
2338 }
2339
2340 if (builtinID == clang::AArch64::BI__builtin_arm_clz ||
2341 builtinID == clang::AArch64::BI__builtin_arm_clz64) {
2342 cgm.errorNYI(expr->getSourceRange(),
2343 std::string("unimplemented AArch64 builtin call: ") +
2344 getContext().BuiltinInfo.getName(builtinID));
2345 return mlir::Value{};
2346 }
2347
2348 if (builtinID == clang::AArch64::BI__builtin_arm_cls) {
2349 cgm.errorNYI(expr->getSourceRange(),
2350 std::string("unimplemented AArch64 builtin call: ") +
2351 getContext().BuiltinInfo.getName(builtinID));
2352 return mlir::Value{};
2353 }
2354 if (builtinID == clang::AArch64::BI__builtin_arm_cls64) {
2355 cgm.errorNYI(expr->getSourceRange(),
2356 std::string("unimplemented AArch64 builtin call: ") +
2357 getContext().BuiltinInfo.getName(builtinID));
2358 return mlir::Value{};
2359 }
2360
2361 if (builtinID == clang::AArch64::BI__builtin_arm_rint32zf ||
2362 builtinID == clang::AArch64::BI__builtin_arm_rint32z) {
2363 cgm.errorNYI(expr->getSourceRange(),
2364 std::string("unimplemented AArch64 builtin call: ") +
2365 getContext().BuiltinInfo.getName(builtinID));
2366 return mlir::Value{};
2367 }
2368
2369 if (builtinID == clang::AArch64::BI__builtin_arm_rint64zf ||
2370 builtinID == clang::AArch64::BI__builtin_arm_rint64z) {
2371 cgm.errorNYI(expr->getSourceRange(),
2372 std::string("unimplemented AArch64 builtin call: ") +
2373 getContext().BuiltinInfo.getName(builtinID));
2374 return mlir::Value{};
2375 }
2376
2377 if (builtinID == clang::AArch64::BI__builtin_arm_rint32xf ||
2378 builtinID == clang::AArch64::BI__builtin_arm_rint32x) {
2379 cgm.errorNYI(expr->getSourceRange(),
2380 std::string("unimplemented AArch64 builtin call: ") +
2381 getContext().BuiltinInfo.getName(builtinID));
2382 return mlir::Value{};
2383 }
2384
2385 if (builtinID == clang::AArch64::BI__builtin_arm_rint64xf ||
2386 builtinID == clang::AArch64::BI__builtin_arm_rint64x) {
2387 cgm.errorNYI(expr->getSourceRange(),
2388 std::string("unimplemented AArch64 builtin call: ") +
2389 getContext().BuiltinInfo.getName(builtinID));
2390 return mlir::Value{};
2391 }
2392
2393 if (builtinID == clang::AArch64::BI__builtin_arm_jcvt) {
2394 cgm.errorNYI(expr->getSourceRange(),
2395 std::string("unimplemented AArch64 builtin call: ") +
2396 getContext().BuiltinInfo.getName(builtinID));
2397 return mlir::Value{};
2398 }
2399
2400 if (builtinID == clang::AArch64::BI__builtin_arm_ld64b ||
2401 builtinID == clang::AArch64::BI__builtin_arm_st64b ||
2402 builtinID == clang::AArch64::BI__builtin_arm_st64bv ||
2403 builtinID == clang::AArch64::BI__builtin_arm_st64bv0) {
2404 cgm.errorNYI(expr->getSourceRange(),
2405 std::string("unimplemented AArch64 builtin call: ") +
2406 getContext().BuiltinInfo.getName(builtinID));
2407 return mlir::Value{};
2408 }
2409
2410 if (builtinID == clang::AArch64::BI__builtin_arm_rndr ||
2411 builtinID == clang::AArch64::BI__builtin_arm_rndrrs) {
2412 cgm.errorNYI(expr->getSourceRange(),
2413 std::string("unimplemented AArch64 builtin call: ") +
2414 getContext().BuiltinInfo.getName(builtinID));
2415 return mlir::Value{};
2416 }
2417
2418 if (builtinID == clang::AArch64::BI__clear_cache) {
2419 cgm.errorNYI(expr->getSourceRange(),
2420 std::string("unimplemented AArch64 builtin call: ") +
2421 getContext().BuiltinInfo.getName(builtinID));
2422 return mlir::Value{};
2423 }
2424
2425 if ((builtinID == clang::AArch64::BI__builtin_arm_ldrex ||
2426 builtinID == clang::AArch64::BI__builtin_arm_ldaex) &&
2427 getContext().getTypeSize(expr->getType()) == 128) {
2428 cgm.errorNYI(expr->getSourceRange(),
2429 std::string("unimplemented AArch64 builtin call: ") +
2430 getContext().BuiltinInfo.getName(builtinID));
2431 return mlir::Value{};
2432 }
2433 if (builtinID == clang::AArch64::BI__builtin_arm_ldrex ||
2434 builtinID == clang::AArch64::BI__builtin_arm_ldaex) {
2435 cgm.errorNYI(expr->getSourceRange(),
2436 std::string("unimplemented AArch64 builtin call: ") +
2437 getContext().BuiltinInfo.getName(builtinID));
2438 return mlir::Value{};
2439 }
2440
2441 if ((builtinID == clang::AArch64::BI__builtin_arm_strex ||
2442 builtinID == clang::AArch64::BI__builtin_arm_stlex) &&
2443 getContext().getTypeSize(expr->getArg(0)->getType()) == 128) {
2444 cgm.errorNYI(expr->getSourceRange(),
2445 std::string("unimplemented AArch64 builtin call: ") +
2446 getContext().BuiltinInfo.getName(builtinID));
2447 return mlir::Value{};
2448 }
2449
2450 if (builtinID == clang::AArch64::BI__builtin_arm_strex ||
2451 builtinID == clang::AArch64::BI__builtin_arm_stlex) {
2452 cgm.errorNYI(expr->getSourceRange(),
2453 std::string("unimplemented AArch64 builtin call: ") +
2454 getContext().BuiltinInfo.getName(builtinID));
2455 return mlir::Value{};
2456 }
2457
2458 if (builtinID == clang::AArch64::BI__getReg ||
2459 builtinID == clang::AArch64::BI__setReg ||
2460 builtinID == clang::AArch64::BI__getRegFp ||
2461 builtinID == clang::AArch64::BI__setRegFp) {
2462 cgm.errorNYI(expr->getSourceRange(),
2463 std::string("unimplemented AArch64 builtin call: ") +
2464 getContext().BuiltinInfo.getName(builtinID));
2465 return mlir::Value{};
2466 }
2467
2468 if (builtinID == clang::AArch64::BI__break) {
2469 cgm.errorNYI(expr->getSourceRange(),
2470 std::string("unimplemented AArch64 builtin call: ") +
2471 getContext().BuiltinInfo.getName(builtinID));
2472 return mlir::Value{};
2473 }
2474
2475 if (builtinID == clang::AArch64::BI__builtin_arm_clrex) {
2476 cgm.errorNYI(expr->getSourceRange(),
2477 std::string("unimplemented AArch64 builtin call: ") +
2478 getContext().BuiltinInfo.getName(builtinID));
2479 return mlir::Value{};
2480 }
2481
2482 if (builtinID == clang::AArch64::BI_ReadWriteBarrier) {
2483 cgm.errorNYI(expr->getSourceRange(),
2484 std::string("unimplemented AArch64 builtin call: ") +
2485 getContext().BuiltinInfo.getName(builtinID));
2486 return mlir::Value{};
2487 }
2488
2489 // CRC32
2490 Intrinsic::ID crcIntrinsicID = Intrinsic::not_intrinsic;
2491 switch (builtinID) {
2492 case clang::AArch64::BI__builtin_arm_crc32b:
2493 crcIntrinsicID = Intrinsic::aarch64_crc32b;
2494 break;
2495 case clang::AArch64::BI__builtin_arm_crc32cb:
2496 crcIntrinsicID = Intrinsic::aarch64_crc32cb;
2497 break;
2498 case clang::AArch64::BI__builtin_arm_crc32h:
2499 crcIntrinsicID = Intrinsic::aarch64_crc32h;
2500 break;
2501 case clang::AArch64::BI__builtin_arm_crc32ch:
2502 crcIntrinsicID = Intrinsic::aarch64_crc32ch;
2503 break;
2504 case clang::AArch64::BI__builtin_arm_crc32w:
2505 crcIntrinsicID = Intrinsic::aarch64_crc32w;
2506 break;
2507 case clang::AArch64::BI__builtin_arm_crc32cw:
2508 crcIntrinsicID = Intrinsic::aarch64_crc32cw;
2509 break;
2510 case clang::AArch64::BI__builtin_arm_crc32d:
2511 crcIntrinsicID = Intrinsic::aarch64_crc32x;
2512 break;
2513 case clang::AArch64::BI__builtin_arm_crc32cd:
2514 crcIntrinsicID = Intrinsic::aarch64_crc32cx;
2515 break;
2516 }
2517
2518 if (crcIntrinsicID != Intrinsic::not_intrinsic) {
2519 cgm.errorNYI(expr->getSourceRange(),
2520 std::string("unimplemented AArch64 builtin call: ") +
2521 getContext().BuiltinInfo.getName(builtinID));
2522 return mlir::Value{};
2523 }
2524
2525 // Memory Operations (MOPS)
2526 if (builtinID == AArch64::BI__builtin_arm_mops_memset_tag) {
2527 cgm.errorNYI(expr->getSourceRange(),
2528 std::string("unimplemented AArch64 builtin call: ") +
2529 getContext().BuiltinInfo.getName(builtinID));
2530 return mlir::Value{};
2531 }
2532
2533 // Memory Tagging Extensions (MTE) Intrinsics
2534 Intrinsic::ID mteIntrinsicID = Intrinsic::not_intrinsic;
2535 switch (builtinID) {
2536 case clang::AArch64::BI__builtin_arm_irg:
2537 mteIntrinsicID = Intrinsic::aarch64_irg;
2538 break;
2539 case clang::AArch64::BI__builtin_arm_addg:
2540 mteIntrinsicID = Intrinsic::aarch64_addg;
2541 break;
2542 case clang::AArch64::BI__builtin_arm_gmi:
2543 mteIntrinsicID = Intrinsic::aarch64_gmi;
2544 break;
2545 case clang::AArch64::BI__builtin_arm_ldg:
2546 mteIntrinsicID = Intrinsic::aarch64_ldg;
2547 break;
2548 case clang::AArch64::BI__builtin_arm_stg:
2549 mteIntrinsicID = Intrinsic::aarch64_stg;
2550 break;
2551 case clang::AArch64::BI__builtin_arm_subp:
2552 mteIntrinsicID = Intrinsic::aarch64_subp;
2553 break;
2554 }
2555
2556 if (mteIntrinsicID != Intrinsic::not_intrinsic) {
2557 cgm.errorNYI(expr->getSourceRange(),
2558 std::string("unimplemented AArch64 builtin call: ") +
2559 getContext().BuiltinInfo.getName(builtinID));
2560 return mlir::Value{};
2561 }
2562
2563 if (builtinID == clang::AArch64::BI__builtin_arm_rsr ||
2564 builtinID == clang::AArch64::BI__builtin_arm_rsr64 ||
2565 builtinID == clang::AArch64::BI__builtin_arm_rsr128 ||
2566 builtinID == clang::AArch64::BI__builtin_arm_rsrp ||
2567 builtinID == clang::AArch64::BI__builtin_arm_wsr ||
2568 builtinID == clang::AArch64::BI__builtin_arm_wsr64 ||
2569 builtinID == clang::AArch64::BI__builtin_arm_wsr128 ||
2570 builtinID == clang::AArch64::BI__builtin_arm_wsrp) {
2571 cgm.errorNYI(expr->getSourceRange(),
2572 std::string("unimplemented AArch64 builtin call: ") +
2573 getContext().BuiltinInfo.getName(builtinID));
2574 return mlir::Value{};
2575 }
2576
2577 if (builtinID == clang::AArch64::BI_ReadStatusReg ||
2578 builtinID == clang::AArch64::BI_WriteStatusReg ||
2579 builtinID == clang::AArch64::BI__sys) {
2580 cgm.errorNYI(expr->getSourceRange(),
2581 std::string("unimplemented AArch64 builtin call: ") +
2582 getContext().BuiltinInfo.getName(builtinID));
2583 return mlir::Value{};
2584 }
2585
2586 if (builtinID == clang::AArch64::BI_AddressOfReturnAddress) {
2587 cgm.errorNYI(expr->getSourceRange(),
2588 std::string("unimplemented AArch64 builtin call: ") +
2589 getContext().BuiltinInfo.getName(builtinID));
2590 return mlir::Value{};
2591 }
2592
2593 if (builtinID == clang::AArch64::BI__builtin_sponentry) {
2594 cgm.errorNYI(expr->getSourceRange(),
2595 std::string("unimplemented AArch64 builtin call: ") +
2596 getContext().BuiltinInfo.getName(builtinID));
2597 return mlir::Value{};
2598 }
2599
2600 if (builtinID == clang::AArch64::BI__mulh ||
2601 builtinID == clang::AArch64::BI__umulh) {
2602 cgm.errorNYI(expr->getSourceRange(),
2603 std::string("unimplemented AArch64 builtin call: ") +
2604 getContext().BuiltinInfo.getName(builtinID));
2605 return mlir::Value{};
2606 }
2607
2608 if (builtinID == AArch64::BI__writex18byte ||
2609 builtinID == AArch64::BI__writex18word ||
2610 builtinID == AArch64::BI__writex18dword ||
2611 builtinID == AArch64::BI__writex18qword) {
2612 cgm.errorNYI(expr->getSourceRange(),
2613 std::string("unimplemented AArch64 builtin call: ") +
2614 getContext().BuiltinInfo.getName(builtinID));
2615 return mlir::Value{};
2616 }
2617
2618 if (builtinID == AArch64::BI__readx18byte ||
2619 builtinID == AArch64::BI__readx18word ||
2620 builtinID == AArch64::BI__readx18dword ||
2621 builtinID == AArch64::BI__readx18qword) {
2622 cgm.errorNYI(expr->getSourceRange(),
2623 std::string("unimplemented AArch64 builtin call: ") +
2624 getContext().BuiltinInfo.getName(builtinID));
2625 return mlir::Value{};
2626 }
2627
2628 if (builtinID == AArch64::BI__addx18byte ||
2629 builtinID == AArch64::BI__addx18word ||
2630 builtinID == AArch64::BI__addx18dword ||
2631 builtinID == AArch64::BI__addx18qword ||
2632 builtinID == AArch64::BI__incx18byte ||
2633 builtinID == AArch64::BI__incx18word ||
2634 builtinID == AArch64::BI__incx18dword ||
2635 builtinID == AArch64::BI__incx18qword) {
2636 cgm.errorNYI(expr->getSourceRange(),
2637 std::string("unimplemented AArch64 builtin call: ") +
2638 getContext().BuiltinInfo.getName(builtinID));
2639 return mlir::Value{};
2640 }
2641
2642 if (builtinID == AArch64::BI_CopyDoubleFromInt64 ||
2643 builtinID == AArch64::BI_CopyFloatFromInt32 ||
2644 builtinID == AArch64::BI_CopyInt32FromFloat ||
2645 builtinID == AArch64::BI_CopyInt64FromDouble) {
2646 cgm.errorNYI(expr->getSourceRange(),
2647 std::string("unimplemented AArch64 builtin call: ") +
2648 getContext().BuiltinInfo.getName(builtinID));
2649 return mlir::Value{};
2650 }
2651
2652 if (builtinID == AArch64::BI_CountLeadingOnes ||
2653 builtinID == AArch64::BI_CountLeadingOnes64 ||
2654 builtinID == AArch64::BI_CountLeadingZeros ||
2655 builtinID == AArch64::BI_CountLeadingZeros64) {
2656 cgm.errorNYI(expr->getSourceRange(),
2657 std::string("unimplemented AArch64 builtin call: ") +
2658 getContext().BuiltinInfo.getName(builtinID));
2659 return mlir::Value{};
2660 }
2661
2662 if (builtinID == AArch64::BI_CountLeadingSigns ||
2663 builtinID == AArch64::BI_CountLeadingSigns64) {
2664 cgm.errorNYI(expr->getSourceRange(),
2665 std::string("unimplemented AArch64 builtin call: ") +
2666 getContext().BuiltinInfo.getName(builtinID));
2667 return mlir::Value{};
2668 }
2669
2670 if (builtinID == AArch64::BI_CountOneBits ||
2671 builtinID == AArch64::BI_CountOneBits64 ||
2672 builtinID == AArch64::BI_CountTrailingZeros ||
2673 builtinID == AArch64::BI_CountTrailingZeros64) {
2674 cgm.errorNYI(expr->getSourceRange(),
2675 std::string("unimplemented AArch64 builtin call: ") +
2676 getContext().BuiltinInfo.getName(builtinID));
2677 return mlir::Value{};
2678 }
2679
2680 if (builtinID == AArch64::BI__prefetch ||
2681 builtinID == AArch64::BI__prefetch2) {
2682 cgm.errorNYI(expr->getSourceRange(),
2683 std::string("unimplemented AArch64 builtin call: ") +
2684 getContext().BuiltinInfo.getName(builtinID));
2685 return mlir::Value{};
2686 }
2687
2688 if (builtinID == AArch64::BI__hlt) {
2689 cgm.errorNYI(expr->getSourceRange(),
2690 std::string("unimplemented AArch64 builtin call: ") +
2691 getContext().BuiltinInfo.getName(builtinID));
2692 return mlir::Value{};
2693 }
2694
2695 if (builtinID == NEON::BI__builtin_neon_vcvth_bf16_f32) {
2696 cgm.errorNYI(expr->getSourceRange(),
2697 std::string("unimplemented AArch64 builtin call: ") +
2698 getContext().BuiltinInfo.getName(builtinID));
2699 return mlir::Value{};
2700 }
2701
2702 // Handle MSVC intrinsics before argument evaluation to prevent double
2703 // evaluation.
2705
2706 // Some intrinsics are equivalent - if they are use the base intrinsic ID.
2707 auto it = llvm::find_if(neonEquivalentIntrinsicMap, [builtinID](auto &p) {
2708 return p.first == builtinID;
2709 });
2710 if (it != end(neonEquivalentIntrinsicMap))
2711 builtinID = it->second;
2712
2713 // Find out if any arguments are required to be integer constant
2714 // expressions.
2716 unsigned iceArguments = 0;
2718 getContext().GetBuiltinType(builtinID, error, &iceArguments);
2719 assert(error == ASTContext::GE_None && "Should not codegen an error");
2721
2722 // Captures the pointer and its alignment for builtins that store/load
2723 // directly through the first argument, i.e. operand 0 (set in the
2724 // arg-gathering loop below, used later when lowering the store/load
2725 // itself).
2726 Address ptrOp0 = Address::invalid();
2727
2728 // Skip extra arguments used to discriminate vector types and that are
2729 // intended for Sema checking.
2730 bool hasExtraArg = hasExtraNeonArgument(builtinID);
2731 unsigned numArgs = expr->getNumArgs() - (hasExtraArg ? 1 : 0);
2732 for (unsigned i = 0, e = numArgs; i != e; i++) {
2733 if (i == 0) {
2734 switch (builtinID) {
2735 case NEON::BI__builtin_neon_vld1_v:
2736 case NEON::BI__builtin_neon_vld1q_v:
2737 case NEON::BI__builtin_neon_vld1_dup_v:
2738 case NEON::BI__builtin_neon_vld1q_dup_v:
2739 case NEON::BI__builtin_neon_vld1_lane_v:
2740 case NEON::BI__builtin_neon_vld1q_lane_v:
2741 case NEON::BI__builtin_neon_vst1_v:
2742 case NEON::BI__builtin_neon_vst1q_v:
2743 case NEON::BI__builtin_neon_vst1_lane_v:
2744 case NEON::BI__builtin_neon_vst1q_lane_v:
2745 case NEON::BI__builtin_neon_vstrq_p128:
2746 case NEON::BI__builtin_neon_vst2_v:
2747 case NEON::BI__builtin_neon_vst2q_v:
2748 case NEON::BI__builtin_neon_vst2_lane_v:
2749 case NEON::BI__builtin_neon_vst2q_lane_v:
2750 case NEON::BI__builtin_neon_vst3_v:
2751 case NEON::BI__builtin_neon_vst3q_v:
2752 case NEON::BI__builtin_neon_vst3_lane_v:
2753 case NEON::BI__builtin_neon_vst3q_lane_v:
2754 case NEON::BI__builtin_neon_vst4_v:
2755 case NEON::BI__builtin_neon_vst4q_v:
2756 case NEON::BI__builtin_neon_vst4_lane_v:
2757 case NEON::BI__builtin_neon_vst4q_lane_v:
2758 // Get the alignment for the argument in addition to the value;
2759 // we'll use it later.
2760 ptrOp0 = emitPointerWithAlignment(expr->getArg(0));
2761 ops.push_back(ptrOp0.getPointer());
2762 continue;
2763 case NEON::BI__builtin_neon_vldap1_lane_s64:
2764 case NEON::BI__builtin_neon_vldap1q_lane_s64:
2765 case NEON::BI__builtin_neon_vstl1_lane_s64:
2766 case NEON::BI__builtin_neon_vstl1q_lane_s64:
2767 cgm.errorNYI(
2768 expr->getSourceRange(),
2769 std::string("unimplemented AArch64 builtin argument handling ") +
2770 getContext().BuiltinInfo.getName(builtinID));
2771 break;
2772 }
2773 }
2774 ops.push_back(
2775 emitScalarOrConstFoldImmArg(iceArguments, i, expr->getArg(i)));
2776 }
2777
2778 const ARMNeonVectorIntrinsicInfo *builtin =
2781 if (builtin)
2782 return emitCommonNeonSISDBuiltinExpr(*this, *builtin, ops, expr,
2783 iceArguments);
2784
2785 // Not all intrinsics handled by the common case work for AArch64 yet, so only
2786 // defer to common code if it's been added to our special map.
2788
2790
2791 const Expr *arg = expr->getArg(expr->getNumArgs() - 1);
2793 // A trailing constant integer is used for discriminating overloaded builtin
2794 // calls. Use it to determine the type of this overloaded NEON intrinsic.
2795 if (std::optional<llvm::APSInt> result =
2796 arg->getIntegerConstantExpr(getContext()))
2797 type = NeonTypeFlags(result->getZExtValue());
2798
2799 bool usgn = type.isUnsigned();
2800
2801 mlir::Location loc = getLoc(expr->getExprLoc());
2802
2803 // Not all intrinsics handled by the common case work for AArch64 yet, so only
2804 // defer to common code if it's been added to our special map.
2805 builtin =
2808 if (builtin)
2810 *this, builtin->BuiltinID, builtin->LLVMIntrinsic,
2811 builtin->AltLLVMIntrinsic, builtin->NameHint, builtin->TypeModifier,
2812 expr, ops);
2813
2814 // Handle non-overloaded intrinsics first.
2815 switch (builtinID) {
2816 default:
2817 break;
2818 case NEON::BI__builtin_neon_vabsh_f16: {
2819 mlir::Type halfTy = builder.getFp16Ty();
2820 return emitNeonCallToOp<cir::FAbsOp>(cgm, builder, {halfTy}, ops,
2821 std::nullopt, halfTy, loc);
2822 }
2823 case NEON::BI__builtin_neon_vaddq_p128: {
2824 cir::VectorType byteTy = cir::VectorType::get(builder.getUInt8Ty(), 16);
2825 ops[0] = builder.createBitcast(ops[0], byteTy);
2826 ops[1] = builder.createBitcast(ops[1], byteTy);
2827 mlir::Value result = builder.createXor(loc, ops[0], ops[1]);
2828 return builder.createBitcast(result, convertType(expr->getType()));
2829 }
2830 case NEON::BI__builtin_neon_vldrq_p128:
2831 cgm.errorNYI(expr->getSourceRange(),
2832 std::string("unimplemented AArch64 builtin call: ") +
2833 getContext().BuiltinInfo.getName(builtinID));
2834 return mlir::Value{};
2835 case NEON::BI__builtin_neon_vstrq_p128: {
2836 builder.createStore(loc, ops[1], ptrOp0);
2837 return nullptr;
2838 }
2839 case NEON::BI__builtin_neon_vcvts_f32_u32:
2840 case NEON::BI__builtin_neon_vcvtd_f64_u64:
2841 case NEON::BI__builtin_neon_vcvts_f32_s32:
2842 case NEON::BI__builtin_neon_vcvtd_f64_s64: {
2843 return builder.createCast(loc, cir::CastKind::int_to_float, ops[0],
2844 convertType(expr->getType()));
2845 }
2846 case NEON::BI__builtin_neon_vcvth_f16_u16:
2847 case NEON::BI__builtin_neon_vcvth_f16_u32:
2848 case NEON::BI__builtin_neon_vcvth_f16_u64:
2849 case NEON::BI__builtin_neon_vcvth_f16_s16:
2850 case NEON::BI__builtin_neon_vcvth_f16_s32:
2851 case NEON::BI__builtin_neon_vcvth_f16_s64:
2852 case NEON::BI__builtin_neon_vcvtah_u16_f16:
2853 case NEON::BI__builtin_neon_vcvtmh_u16_f16:
2854 case NEON::BI__builtin_neon_vcvtnh_u16_f16:
2855 case NEON::BI__builtin_neon_vcvtph_u16_f16:
2856 case NEON::BI__builtin_neon_vcvth_u16_f16:
2857 case NEON::BI__builtin_neon_vcvtah_s16_f16:
2858 case NEON::BI__builtin_neon_vcvtmh_s16_f16:
2859 case NEON::BI__builtin_neon_vcvtnh_s16_f16:
2860 case NEON::BI__builtin_neon_vcvtph_s16_f16:
2861 case NEON::BI__builtin_neon_vcvth_s16_f16:
2862 case NEON::BI__builtin_neon_vcaleh_f16:
2863 case NEON::BI__builtin_neon_vcalth_f16:
2864 case NEON::BI__builtin_neon_vcageh_f16:
2865 case NEON::BI__builtin_neon_vcagth_f16:
2866 case NEON::BI__builtin_neon_vcvth_n_s16_f16:
2867 case NEON::BI__builtin_neon_vcvth_n_u16_f16:
2868 case NEON::BI__builtin_neon_vcvth_n_f16_s16:
2869 case NEON::BI__builtin_neon_vcvth_n_f16_u16:
2870 case NEON::BI__builtin_neon_vpaddd_s64:
2871 case NEON::BI__builtin_neon_vpaddd_f64:
2872 case NEON::BI__builtin_neon_vpadds_f32:
2873 cgm.errorNYI(expr->getSourceRange(),
2874 std::string("unimplemented AArch64 builtin call: ") +
2875 getContext().BuiltinInfo.getName(builtinID));
2876 return mlir::Value{};
2877 case NEON::BI__builtin_neon_vceqzd_s64:
2878 case NEON::BI__builtin_neon_vceqzd_f64:
2879 case NEON::BI__builtin_neon_vceqzs_f32:
2880 case NEON::BI__builtin_neon_vceqzh_f16:
2882 *this, builder, loc, ops[0],
2883 convertType(expr->getCallReturnType(getContext())), cir::CmpOpKind::eq);
2884 case NEON::BI__builtin_neon_vcgezd_s64:
2885 case NEON::BI__builtin_neon_vcgezd_f64:
2886 case NEON::BI__builtin_neon_vcgezs_f32:
2887 case NEON::BI__builtin_neon_vcgezh_f16:
2888 case NEON::BI__builtin_neon_vclezd_s64:
2889 case NEON::BI__builtin_neon_vclezd_f64:
2890 case NEON::BI__builtin_neon_vclezs_f32:
2891 case NEON::BI__builtin_neon_vclezh_f16:
2892 case NEON::BI__builtin_neon_vcgtzd_s64:
2893 case NEON::BI__builtin_neon_vcgtzd_f64:
2894 case NEON::BI__builtin_neon_vcgtzs_f32:
2895 case NEON::BI__builtin_neon_vcgtzh_f16:
2896 case NEON::BI__builtin_neon_vcltzd_s64:
2897 case NEON::BI__builtin_neon_vcltzd_f64:
2898 case NEON::BI__builtin_neon_vcltzs_f32:
2899 case NEON::BI__builtin_neon_vcltzh_f16:
2900 case NEON::BI__builtin_neon_vceqzd_u64: {
2902 *this, builder, loc, ops[0],
2903 convertType(expr->getCallReturnType(getContext())), cir::CmpOpKind::eq);
2904 }
2905 case NEON::BI__builtin_neon_vceqd_f64:
2906 case NEON::BI__builtin_neon_vcled_f64:
2907 case NEON::BI__builtin_neon_vcltd_f64:
2908 case NEON::BI__builtin_neon_vcged_f64:
2909 case NEON::BI__builtin_neon_vcgtd_f64:
2910 case NEON::BI__builtin_neon_vceqs_f32:
2911 case NEON::BI__builtin_neon_vcles_f32:
2912 case NEON::BI__builtin_neon_vclts_f32:
2913 case NEON::BI__builtin_neon_vcges_f32:
2914 case NEON::BI__builtin_neon_vcgts_f32:
2915 case NEON::BI__builtin_neon_vceqh_f16:
2916 case NEON::BI__builtin_neon_vcleh_f16:
2917 case NEON::BI__builtin_neon_vclth_f16:
2918 case NEON::BI__builtin_neon_vcgeh_f16:
2919 case NEON::BI__builtin_neon_vcgth_f16:
2920 case NEON::BI__builtin_neon_vceqd_s64:
2921 case NEON::BI__builtin_neon_vceqd_u64:
2922 case NEON::BI__builtin_neon_vcgtd_s64:
2923 case NEON::BI__builtin_neon_vcgtd_u64:
2924 case NEON::BI__builtin_neon_vcltd_s64:
2925 case NEON::BI__builtin_neon_vcltd_u64:
2926 case NEON::BI__builtin_neon_vcged_u64:
2927 case NEON::BI__builtin_neon_vcged_s64:
2928 case NEON::BI__builtin_neon_vcled_u64:
2929 case NEON::BI__builtin_neon_vcled_s64:
2930 cgm.errorNYI(expr->getSourceRange(),
2931 std::string("unimplemented AArch64 builtin call: ") +
2932 getContext().BuiltinInfo.getName(builtinID));
2933 return mlir::Value{};
2934 case NEON::BI__builtin_neon_vnegd_s64: {
2935 return builder.createNeg(loc, ops[0]);
2936 }
2937 case NEON::BI__builtin_neon_vnegh_f16: {
2938 return builder.createFNeg(loc, ops[0]);
2939 }
2940 case NEON::BI__builtin_neon_vtstd_s64:
2941 case NEON::BI__builtin_neon_vtstd_u64:
2942 cgm.errorNYI(expr->getSourceRange(),
2943 std::string("unimplemented AArch64 builtin call: ") +
2944 getContext().BuiltinInfo.getName(builtinID));
2945 return mlir::Value{};
2946 case NEON::BI__builtin_neon_vset_lane_i8:
2947 case NEON::BI__builtin_neon_vset_lane_i16:
2948 case NEON::BI__builtin_neon_vset_lane_i32:
2949 case NEON::BI__builtin_neon_vset_lane_i64:
2950 case NEON::BI__builtin_neon_vset_lane_bf16:
2951 case NEON::BI__builtin_neon_vset_lane_f32:
2952 case NEON::BI__builtin_neon_vsetq_lane_i8:
2953 case NEON::BI__builtin_neon_vsetq_lane_i16:
2954 case NEON::BI__builtin_neon_vsetq_lane_i32:
2955 case NEON::BI__builtin_neon_vsetq_lane_i64:
2956 case NEON::BI__builtin_neon_vsetq_lane_bf16:
2957 case NEON::BI__builtin_neon_vsetq_lane_f32:
2958 case NEON::BI__builtin_neon_vset_lane_f64:
2959 case NEON::BI__builtin_neon_vset_lane_mf8:
2960 case NEON::BI__builtin_neon_vsetq_lane_mf8:
2961 case NEON::BI__builtin_neon_vsetq_lane_f64:
2962 return cir::VecInsertOp::create(builder, loc, ops[1], ops[0], ops[2]);
2963 case NEON::BI__builtin_neon_vget_lane_i8:
2964 case NEON::BI__builtin_neon_vdupb_lane_i8:
2965 case NEON::BI__builtin_neon_vgetq_lane_i8:
2966 case NEON::BI__builtin_neon_vdupb_laneq_i8:
2967 case NEON::BI__builtin_neon_vget_lane_mf8:
2968 case NEON::BI__builtin_neon_vdupb_lane_mf8:
2969 case NEON::BI__builtin_neon_vgetq_lane_mf8:
2970 case NEON::BI__builtin_neon_vdupb_laneq_mf8:
2971 case NEON::BI__builtin_neon_vget_lane_i16:
2972 case NEON::BI__builtin_neon_vduph_lane_i16:
2973 case NEON::BI__builtin_neon_vgetq_lane_i16:
2974 case NEON::BI__builtin_neon_vduph_laneq_i16:
2975 case NEON::BI__builtin_neon_vget_lane_i32:
2976 case NEON::BI__builtin_neon_vdups_lane_i32:
2977 case NEON::BI__builtin_neon_vdups_lane_f32:
2978 case NEON::BI__builtin_neon_vgetq_lane_i32:
2979 case NEON::BI__builtin_neon_vdups_laneq_i32:
2980 case NEON::BI__builtin_neon_vget_lane_i64:
2981 case NEON::BI__builtin_neon_vdupd_lane_i64:
2982 case NEON::BI__builtin_neon_vdupd_lane_f64:
2983 case NEON::BI__builtin_neon_vgetq_lane_i64:
2984 case NEON::BI__builtin_neon_vdupd_laneq_i64:
2985 case NEON::BI__builtin_neon_vget_lane_f32:
2986 case NEON::BI__builtin_neon_vget_lane_f64:
2987 case NEON::BI__builtin_neon_vgetq_lane_f32:
2988 case NEON::BI__builtin_neon_vdups_laneq_f32:
2989 case NEON::BI__builtin_neon_vgetq_lane_f64:
2990 case NEON::BI__builtin_neon_vdupd_laneq_f64:
2991 return cir::VecExtractOp::create(builder, loc, ops[0],
2992 emitScalarExpr(expr->getArg(1)));
2993 case NEON::BI__builtin_neon_vaddh_f16:
2994 return builder.createFAdd(loc, ops[0], ops[1]);
2995 case NEON::BI__builtin_neon_vsubh_f16:
2996 return builder.createFSub(loc, ops[0], ops[1]);
2997 case NEON::BI__builtin_neon_vmulh_f16:
2998 return builder.createFMul(loc, ops[0], ops[1]);
2999 case NEON::BI__builtin_neon_vdivh_f16:
3000 return builder.createFDiv(loc, ops[0], ops[1]);
3001 case NEON::BI__builtin_neon_vfmah_f16: {
3002 // NEON intrinsic puts accumulator first, unlike fma.
3003 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3004 mlir::Type ty = convertType(expr->getType());
3005 return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, ops,
3006 std::nullopt, ty, loc);
3007 }
3008 case NEON::BI__builtin_neon_vfmsh_f16: {
3009 // NEON intrinsic puts accumulator first, unlike fma.
3010 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3011 ops[0] = builder.createFNeg(loc, ops[0]);
3012 mlir::Type ty = convertType(expr->getType());
3013 return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, ops,
3014 std::nullopt, ty, loc);
3015 }
3016 case NEON::BI__builtin_neon_vaddd_s64:
3017 case NEON::BI__builtin_neon_vaddd_u64:
3018 return builder.createAdd(loc, ops[0], ops[1]);
3019 case NEON::BI__builtin_neon_vsubd_s64:
3020 case NEON::BI__builtin_neon_vsubd_u64:
3021 return builder.createSub(loc, ops[0], ops[1]);
3022 case NEON::BI__builtin_neon_vqdmlalh_s16:
3023 case NEON::BI__builtin_neon_vqdmlslh_s16:
3024 cgm.errorNYI(expr->getSourceRange(),
3025 std::string("unimplemented AArch64 builtin call: ") +
3026 getContext().BuiltinInfo.getName(builtinID));
3027 return mlir::Value{};
3028 case NEON::BI__builtin_neon_vqshlud_n_s64: {
3029 cir::IntType int64Type = builder.getSInt64Ty();
3030 ops[1] = builder.getSInt64(getZExtIntValueFromConstOp(ops[1]), loc);
3031 return emitNeonCall(cgm, builder, {int64Type, int64Type}, ops,
3032 "aarch64.neon.sqshlu", convertType(expr->getType()),
3033 loc);
3034 }
3035 case NEON::BI__builtin_neon_vqshld_n_u64:
3036 case NEON::BI__builtin_neon_vqshld_n_s64: {
3037 cir::IntType int64Type = builtinID == NEON::BI__builtin_neon_vqshld_n_u64
3038 ? builder.getUInt64Ty()
3039 : builder.getSInt64Ty();
3040 llvm::StringRef intrinsicName =
3041 builtinID == NEON::BI__builtin_neon_vqshld_n_u64 ? "aarch64.neon.uqshl"
3042 : "aarch64.neon.sqshl";
3043 ops[1] = builder.getSInt64(getZExtIntValueFromConstOp(ops[1]), loc);
3044 return emitNeonCall(cgm, builder, {int64Type, int64Type}, ops,
3045 intrinsicName, convertType(expr->getType()), loc);
3046 }
3047 case NEON::BI__builtin_neon_vrshrd_n_u64:
3048 case NEON::BI__builtin_neon_vrshrd_n_s64: {
3049 llvm::StringRef intrName = builtinID == NEON::BI__builtin_neon_vrshrd_n_s64
3050 ? "aarch64.neon.srshl"
3051 : "aarch64.neon.urshl";
3052 cir::IntType int64Ty = builtinID == NEON::BI__builtin_neon_vqshld_n_u64
3053 ? builder.getUInt64Ty()
3054 : builder.getSInt64Ty();
3055 int64_t sv = -cast<cir::IntAttr>(
3056 cast<cir::ConstantOp>(ops[1].getDefiningOp()).getValue())
3057 .getSInt();
3058 ops[1] = builder.getSInt64(sv, loc);
3059 return emitNeonCall(cgm, builder, {int64Ty, builder.getSInt64Ty()}, ops,
3060 intrName, int64Ty, loc);
3061 }
3062 case NEON::BI__builtin_neon_vrsrad_n_u64:
3063 case NEON::BI__builtin_neon_vrsrad_n_s64: {
3064 cir::IntType int64Type = builtinID == NEON::BI__builtin_neon_vrsrad_n_u64
3065 ? builder.getUInt64Ty()
3066 : builder.getSInt64Ty();
3067 ops[2] = builder.createNeg(loc, ops[2]);
3068 const StringRef intrName = builtinID == NEON::BI__builtin_neon_vrsrad_n_u64
3069 ? "aarch64.neon.urshl"
3070 : "aarch64.neon.srshl";
3071
3073 ops[1], builder.createIntCast(ops[2], builder.getSInt64Ty())};
3074 ops[1] = builder.emitIntrinsicCallOp(loc, intrName, int64Type, args);
3075 return builder.createAdd(loc, ops[0],
3076 builder.createBitcast(ops[1], int64Type));
3077 }
3078 case NEON::BI__builtin_neon_vshld_n_s64:
3079 case NEON::BI__builtin_neon_vshld_n_u64: {
3080 auto loc = getLoc(expr->getExprLoc());
3081 std::optional<llvm::APSInt> amt =
3082 expr->getArg(1)->getIntegerConstantExpr(getContext());
3083 assert(amt && "Expected argument to be a constant");
3084 return builder.createShiftLeft(loc, ops[0], amt->getZExtValue());
3085 }
3086 case NEON::BI__builtin_neon_vshrd_n_s64: {
3087 std::optional<llvm::APSInt> amt =
3088 expr->getArg(1)->getIntegerConstantExpr(getContext());
3089 assert(amt && "Expected argument to be a constant");
3090 return builder.createShiftRight(
3091 loc, ops[0], std::min(static_cast<uint64_t>(63), amt->getZExtValue()));
3092 }
3093 case NEON::BI__builtin_neon_vshrd_n_u64: {
3094 std::optional<llvm::APSInt> amt =
3095 expr->getArg(1)->getIntegerConstantExpr(getContext());
3096 assert(amt && "Expected argument to be a constant");
3097 uint64_t shiftAmt = amt->getZExtValue();
3098 // Right-shifting an unsigned value by its size yields 0.
3099 if (shiftAmt == 64)
3100 return builder.getConstInt(loc, builder.getUInt64Ty(), 0);
3101 return builder.createShiftRight(loc, ops[0], shiftAmt);
3102 }
3103 case NEON::BI__builtin_neon_vsrad_n_s64: {
3104 std::optional<llvm::APSInt> amt =
3105 expr->getArg(2)->getIntegerConstantExpr(getContext());
3106 assert(amt && "Expected argument to be a constant");
3107 uint64_t shiftAmt =
3108 std::min(static_cast<uint64_t>(63), amt->getZExtValue());
3109 mlir::Value shifted =
3110 builder.createShiftRight(loc, ops[1], static_cast<unsigned>(shiftAmt));
3111 return builder.createAdd(loc, ops[0], shifted);
3112 }
3113 case NEON::BI__builtin_neon_vsrad_n_u64: {
3114 std::optional<llvm::APSInt> amt =
3115 expr->getArg(2)->getIntegerConstantExpr(getContext());
3116 assert(amt && "Expected argument to be a constant");
3117 uint64_t shiftAmt = amt->getZExtValue();
3118 // Right-shifting an unsigned value by its size yields 0, so a + 0 = a.
3119 if (shiftAmt == 64)
3120 return ops[0];
3121 mlir::Value shifted =
3122 builder.createShiftRight(loc, ops[1], static_cast<unsigned>(shiftAmt));
3123 return builder.createAdd(loc, ops[0], shifted);
3124 }
3125 case NEON::BI__builtin_neon_vqdmlalh_lane_s16:
3126 case NEON::BI__builtin_neon_vqdmlalh_laneq_s16:
3127 case NEON::BI__builtin_neon_vqdmlslh_lane_s16:
3128 case NEON::BI__builtin_neon_vqdmlslh_laneq_s16:
3129 case NEON::BI__builtin_neon_vqdmlals_s32:
3130 case NEON::BI__builtin_neon_vqdmlsls_s32:
3131 case NEON::BI__builtin_neon_vqdmlals_lane_s32:
3132 case NEON::BI__builtin_neon_vqdmlals_laneq_s32:
3133 case NEON::BI__builtin_neon_vqdmlsls_lane_s32:
3134 case NEON::BI__builtin_neon_vqdmlsls_laneq_s32: {
3135 cgm.errorNYI(expr->getSourceRange(),
3136 std::string("unimplemented AArch64 builtin call: ") +
3137 getContext().BuiltinInfo.getName(builtinID));
3138 return mlir::Value{};
3139 }
3140 case NEON::BI__builtin_neon_vget_lane_bf16:
3141 case NEON::BI__builtin_neon_vduph_lane_bf16:
3142 case NEON::BI__builtin_neon_vduph_lane_f16:
3143 case NEON::BI__builtin_neon_vgetq_lane_bf16:
3144 case NEON::BI__builtin_neon_vduph_laneq_bf16:
3145 case NEON::BI__builtin_neon_vduph_laneq_f16: {
3146 return cir::VecExtractOp::create(builder, loc, ops[0], ops[1]);
3147 }
3148 case NEON::BI__builtin_neon_vcvt_bf16_f32:
3149 case NEON::BI__builtin_neon_vcvtq_low_bf16_f32:
3150 case NEON::BI__builtin_neon_vcvtq_high_bf16_f32:
3151 cgm.errorNYI(expr->getSourceRange(),
3152 std::string("unimplemented AArch64 builtin call: ") +
3153 getContext().BuiltinInfo.getName(builtinID));
3154 return mlir::Value{};
3155 case NEON::BI__builtin_neon_vcvt_f16_f32: {
3156 auto v4f32 = cir::VectorType::get(cgm.floatTy, 4);
3157 auto v4f16 = cir::VectorType::get(cgm.fP16Ty, 4);
3158 return builder.createFloatingCast(builder.createBitcast(ops[0], v4f32),
3159 v4f16);
3160 }
3161 case NEON::BI__builtin_neon_vcvt_f32_f16: {
3162 auto v4f32 = cir::VectorType::get(cgm.floatTy, 4);
3163 auto v4f16 = cir::VectorType::get(cgm.fP16Ty, 4);
3164 return builder.createFloatingCast(builder.createBitcast(ops[0], v4f16),
3165 v4f32);
3166 }
3167 case clang::AArch64::BI_InterlockedAdd:
3168 case clang::AArch64::BI_InterlockedAdd_acq:
3169 case clang::AArch64::BI_InterlockedAdd_rel:
3170 case clang::AArch64::BI_InterlockedAdd_nf:
3171 case clang::AArch64::BI_InterlockedAdd64:
3172 case clang::AArch64::BI_InterlockedAdd64_acq:
3173 case clang::AArch64::BI_InterlockedAdd64_rel:
3174 case clang::AArch64::BI_InterlockedAdd64_nf:
3175 cgm.errorNYI(expr->getSourceRange(),
3176 std::string("unimplemented AArch64 builtin call: ") +
3177 getContext().BuiltinInfo.getName(builtinID));
3178 return mlir::Value{};
3179 }
3180
3181 cir::VectorType ty = getNeonType(this, type);
3182 if (!ty)
3183 return nullptr;
3184
3185 llvm::StringRef intrName;
3186
3187 switch (builtinID) {
3188 default:
3189 return std::nullopt;
3190 case NEON::BI__builtin_neon_vbsl_v:
3191 case NEON::BI__builtin_neon_vbslq_v: {
3192
3193 cir::VectorType bitTy = getIntVecFromVecTy(builder, ty);
3194 ops[0] = builder.createBitcast(ops[0], bitTy);
3195 ops[1] = builder.createBitcast(ops[1], bitTy);
3196 ops[2] = builder.createBitcast(ops[2], bitTy);
3197
3198 ops[1] = builder.createAnd(loc, ops[0], ops[1]);
3199 ops[2] = builder.createAnd(loc, builder.createNot(ops[0]), ops[2]);
3200 ops[0] = builder.createOr(loc, ops[1], ops[2]);
3201 return builder.createBitcast(ops[0], ty);
3202 }
3203 case NEON::BI__builtin_neon_vfma_lane_v:
3204 case NEON::BI__builtin_neon_vfmaq_lane_v: {
3205 mlir::Value addend = builder.createBitcast(ops[0], ty);
3206 mlir::Value multiplicand = builder.createBitcast(ops[1], ty);
3207 // For vfmaq_lane, the lane source operand is the non-quad vector, so it has
3208 // half as many lanes as the quad result vector. For vfma_lane, it has the
3209 // same shape as the result vector.
3210 cir::VectorType sourceTy = cir::VectorType::get(
3211 ty.getElementType(), builtinID == NEON::BI__builtin_neon_vfmaq_lane_v
3212 ? ty.getSize() / 2
3213 : ty.getSize());
3214 mlir::Value laneSource = builder.createBitcast(ops[2], sourceTy);
3215 laneSource = emitNeonSplat(builder, loc, laneSource, ops[3], ty.getSize());
3216
3217 llvm::SmallVector<mlir::Value> fmaOps = {multiplicand, laneSource, addend};
3218 return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, fmaOps,
3219 std::nullopt, ty, loc);
3220 }
3221 case NEON::BI__builtin_neon_vfma_laneq_v: {
3222 // v1f64 fma should be mapped to Neon scalar f64 fma.
3223 if (ty.getElementType() == cgm.doubleTy) {
3224 mlir::Value addend = builder.createBitcast(ops[0], cgm.doubleTy);
3225 mlir::Value multiplicand = builder.createBitcast(ops[1], cgm.doubleTy);
3226 // The laneq source operand is float64x2_t, so the source vector has two
3227 // double lanes.
3228 cir::VectorType sourceTy = cir::VectorType::get(cgm.doubleTy, 2);
3229 mlir::Value laneSource = builder.createBitcast(ops[2], sourceTy);
3230 laneSource = builder.createExtractElement(
3231 loc, laneSource,
3232 static_cast<uint64_t>(getIntValueFromConstOp(ops[3])));
3233
3234 llvm::SmallVector<mlir::Value> fmaOps = {multiplicand, laneSource,
3235 addend};
3236 return builder.createBitcast(
3238 cgm, builder, {cgm.doubleTy, cgm.doubleTy, cgm.doubleTy}, fmaOps,
3239 std::nullopt, cgm.doubleTy, loc),
3240 ty);
3241 }
3242
3243 mlir::Value addend = builder.createBitcast(ops[0], ty);
3244 mlir::Value multiplicand = builder.createBitcast(ops[1], ty);
3245 // The laneq source operand is the quad vector, so it has twice as many
3246 // lanes as the non-quad result vector.
3247 cir::VectorType sourceTy =
3248 cir::VectorType::get(ty.getElementType(), ty.getSize() * 2);
3249 mlir::Value laneSource = builder.createBitcast(ops[2], sourceTy);
3250 laneSource = emitNeonSplat(builder, loc, laneSource, ops[3], ty.getSize());
3251
3252 llvm::SmallVector<mlir::Value> fmaOps = {laneSource, multiplicand, addend};
3253 return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, fmaOps,
3254 std::nullopt, ty, loc);
3255 }
3256 case NEON::BI__builtin_neon_vfmaq_laneq_v: {
3257 mlir::Value addend = builder.createBitcast(ops[0], ty);
3258 mlir::Value multiplicand = builder.createBitcast(ops[1], ty);
3259 mlir::Value laneSource = builder.createBitcast(ops[2], ty);
3260 laneSource = emitNeonSplat(builder, loc, laneSource, ops[3], ty.getSize());
3261
3262 llvm::SmallVector<mlir::Value> fmaOps = {laneSource, multiplicand, addend};
3263 return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, fmaOps,
3264 std::nullopt, ty, loc);
3265 }
3266 case NEON::BI__builtin_neon_vfmah_lane_f16:
3267 case NEON::BI__builtin_neon_vfmas_lane_f32:
3268 case NEON::BI__builtin_neon_vfmah_laneq_f16:
3269 case NEON::BI__builtin_neon_vfmas_laneq_f32: {
3270 // Scalar lane/laneq forms use one selected element from the lane source.
3271 mlir::Value laneSource = builder.createExtractElement(
3272 loc, ops[2], static_cast<uint64_t>(getIntValueFromConstOp(ops[3])));
3273
3274 llvm::SmallVector<mlir::Value> fmaOps = {ops[1], laneSource, ops[0]};
3275 mlir::Type ty = convertType(expr->getType());
3276 return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, fmaOps,
3277 std::nullopt, ty, loc);
3278 }
3279 case NEON::BI__builtin_neon_vfmad_lane_f64:
3280 case NEON::BI__builtin_neon_vfmad_laneq_f64: {
3281 // The lane source operand is float64x1_t for lane forms and float64x2_t
3282 // for laneq forms.
3283 mlir::Value laneSource = builder.createExtractElement(
3284 loc, ops[2], static_cast<uint64_t>(getIntValueFromConstOp(ops[3])));
3285
3286 llvm::SmallVector<mlir::Value> fmaOps = {ops[1], laneSource, ops[0]};
3288 cgm, builder, {cgm.doubleTy, cgm.doubleTy, cgm.doubleTy}, fmaOps,
3289 std::nullopt, cgm.doubleTy, loc);
3290 }
3291 case NEON::BI__builtin_neon_vmull_v: {
3292 intrName = usgn ? "aarch64.neon.umull" : "aarch64.neon.smull";
3293 if (type.isPoly())
3294 intrName = "aarch64.neon.pmull";
3295 cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
3296 ty, /*isExtended*/ false, !usgn);
3297 return emitNeonCall(cgm, builder, {argTy, argTy}, ops, intrName, ty, loc);
3298 }
3299 case NEON::BI__builtin_neon_vmax_v:
3300 case NEON::BI__builtin_neon_vmaxq_v:
3301 intrName = usgn ? "umax" : "smax";
3302 if (cir::isFPOrVectorOfFPType(ty))
3303 intrName = "aarch64.neon.fmax";
3304 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3305 case NEON::BI__builtin_neon_vmaxh_f16: {
3306 auto halfTy = builder.getFp16Ty();
3307 return builder.emitIntrinsicCallOp(loc, "aarch64.neon.fmax", halfTy, ops);
3308 }
3309 case NEON::BI__builtin_neon_vmin_v:
3310 case NEON::BI__builtin_neon_vminq_v:
3311 intrName = usgn ? "umin" : "smin";
3312 if (cir::isFPOrVectorOfFPType(ty))
3313 intrName = "aarch64.neon.fmin";
3314 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3315 case NEON::BI__builtin_neon_vminh_f16: {
3316 auto halfTy = builder.getFp16Ty();
3317 return builder.emitIntrinsicCallOp(loc, "aarch64.neon.fmin", halfTy, ops);
3318 }
3319 case NEON::BI__builtin_neon_vabd_v:
3320 case NEON::BI__builtin_neon_vabdq_v:
3321 intrName = usgn ? "aarch64.neon.uabd" : "aarch64.neon.sabd";
3322 if (cir::isFPOrVectorOfFPType(ty))
3323 intrName = "aarch64.neon.fabd";
3324 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3325 case NEON::BI__builtin_neon_vpadal_v:
3326 case NEON::BI__builtin_neon_vpadalq_v: {
3327 intrName = usgn ? "aarch64.neon.uaddlp" : "aarch64.neon.saddlp";
3328 llvm::SmallVector<mlir::Value> inputs{ops[1]};
3329 mlir::Value pairwiseSum =
3330 emitNeonCall(cgm, builder, {getNeonPairwiseWidenInputType(ty, usgn)},
3331 inputs, intrName, ty, loc);
3332 mlir::Value accumValue = builder.createBitcast(loc, ops[0], ty);
3333 return cir::AddOp::create(builder, loc, ty, pairwiseSum, accumValue);
3334 }
3335 case NEON::BI__builtin_neon_vpmin_v:
3336 case NEON::BI__builtin_neon_vpminq_v:
3337 intrName = usgn ? "aarch64.neon.uminp" : "aarch64.neon.sminp";
3338 if (cir::isFPOrVectorOfFPType(ty))
3339 intrName = "aarch64.neon.fminp";
3340 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3341 case NEON::BI__builtin_neon_vpmax_v:
3342 case NEON::BI__builtin_neon_vpmaxq_v:
3343 intrName = usgn ? "aarch64.neon.umaxp" : "aarch64.neon.smaxp";
3344 if (cir::isFPOrVectorOfFPType(ty))
3345 intrName = "aarch64.neon.fmaxp";
3346 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3347 case NEON::BI__builtin_neon_vminnm_v:
3348 case NEON::BI__builtin_neon_vminnmq_v:
3349 intrName = "aarch64.neon.fminnm";
3350 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3351 case NEON::BI__builtin_neon_vminnmh_f16: {
3352 auto halfTy = builder.getFp16Ty();
3353 return builder.emitIntrinsicCallOp(loc, "aarch64.neon.fminnm", halfTy, ops);
3354 }
3355 case NEON::BI__builtin_neon_vmaxnm_v:
3356 case NEON::BI__builtin_neon_vmaxnmq_v:
3357 intrName = "aarch64.neon.fmaxnm";
3358 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3359 case NEON::BI__builtin_neon_vmaxnmh_f16: {
3360 auto halfTy = builder.getFp16Ty();
3361 return builder.emitIntrinsicCallOp(loc, "aarch64.neon.fmaxnm", halfTy, ops);
3362 }
3363 case NEON::BI__builtin_neon_vrecpss_f32:
3364 case NEON::BI__builtin_neon_vrecpsd_f64:
3365 cgm.errorNYI(expr->getSourceRange(),
3366 std::string("unimplemented AArch64 builtin call: ") +
3367 getContext().BuiltinInfo.getName(builtinID));
3368 return mlir::Value{};
3369 case NEON::BI__builtin_neon_vrecpsh_f16: {
3370 auto halfTy = builder.getFp16Ty();
3371 return builder.emitIntrinsicCallOp(loc, "aarch64.neon.frecps", halfTy, ops);
3372 }
3373 case NEON::BI__builtin_neon_vqshrun_n_v: {
3374 cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
3375 ty, /*isExtended=*/true, /*isSigned=*/true);
3376 return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops,
3377 "aarch64.neon.sqshrun", ty, loc);
3378 }
3379 case NEON::BI__builtin_neon_vqrshrun_n_v: {
3380 cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
3381 ty, /*isExtended=*/true, /*isSigned=*/true);
3382 return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops,
3383 "aarch64.neon.sqrshrun", ty, loc);
3384 }
3385 case NEON::BI__builtin_neon_vqshrn_n_v: {
3386 cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
3387 ty, /*isExtended=*/true, /*isSigned=*/!usgn);
3388 llvm::StringRef intrName =
3389 usgn ? "aarch64.neon.uqshrn" : "aarch64.neon.sqshrn";
3390 return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops, intrName, ty,
3391 loc);
3392 }
3393 case NEON::BI__builtin_neon_vrshrn_n_v:
3394 cgm.errorNYI(expr->getSourceRange(),
3395 std::string("unimplemented AArch64 builtin call: ") +
3396 getContext().BuiltinInfo.getName(builtinID));
3397 return mlir::Value{};
3398 case NEON::BI__builtin_neon_vqrshrn_n_v: {
3399 cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
3400 ty, /*isExtended=*/true, /*isSigned=*/!usgn);
3401 llvm::StringRef intrName =
3402 usgn ? "aarch64.neon.uqrshrn" : "aarch64.neon.sqrshrn";
3403 return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops, intrName, ty,
3404 loc);
3405 }
3406 case NEON::BI__builtin_neon_vrndah_f16: {
3408 mlir::Type halfTy = builder.getFp16Ty();
3409 return emitNeonCallToOp<cir::RoundOp>(cgm, builder, {halfTy}, ops,
3410 std::nullopt, halfTy, loc);
3411 }
3412 case NEON::BI__builtin_neon_vrnda_v:
3413 case NEON::BI__builtin_neon_vrndaq_v:
3415 return emitNeonCallToOp<cir::RoundOp>(cgm, builder, {ty}, ops, std::nullopt,
3416 ty, loc);
3417 case NEON::BI__builtin_neon_vrndih_f16: {
3419 mlir::Type halfTy = builder.getFp16Ty();
3420 return emitNeonCallToOp<cir::NearbyintOp>(cgm, builder, {halfTy}, ops,
3421 std::nullopt, halfTy, loc);
3422 }
3423 case NEON::BI__builtin_neon_vrndmh_f16: {
3425 mlir::Type halfTy = builder.getFp16Ty();
3426 return emitNeonCallToOp<cir::FloorOp>(cgm, builder, {halfTy}, ops,
3427 std::nullopt, halfTy, loc);
3428 }
3429 case NEON::BI__builtin_neon_vrndm_v:
3430 case NEON::BI__builtin_neon_vrndmq_v:
3432 return emitNeonCallToOp<cir::FloorOp>(cgm, builder, {ty}, ops, std::nullopt,
3433 ty, loc);
3434 case NEON::BI__builtin_neon_vrndnh_f16: {
3436 mlir::Type halfTy = builder.getFp16Ty();
3437 return emitNeonCallToOp<cir::RoundEvenOp>(cgm, builder, {halfTy}, ops,
3438 std::nullopt, halfTy, loc);
3439 }
3440 case NEON::BI__builtin_neon_vrndn_v:
3441 case NEON::BI__builtin_neon_vrndnq_v:
3443 return emitNeonCallToOp<cir::RoundEvenOp>(cgm, builder, {ty}, ops,
3444 std::nullopt, ty, loc);
3445 case NEON::BI__builtin_neon_vrndns_f32: {
3447 mlir::Type floatTy = builder.getSingleTy();
3448 return emitNeonCallToOp<cir::RoundEvenOp>(cgm, builder, {floatTy}, ops,
3449 std::nullopt, floatTy, loc);
3450 }
3451 case NEON::BI__builtin_neon_vrndph_f16: {
3453 mlir::Type halfTy = builder.getFp16Ty();
3454 return emitNeonCallToOp<cir::CeilOp>(cgm, builder, {halfTy}, ops,
3455 std::nullopt, halfTy, loc);
3456 }
3457 case NEON::BI__builtin_neon_vrndp_v:
3458 case NEON::BI__builtin_neon_vrndpq_v:
3460 return emitNeonCallToOp<cir::CeilOp>(cgm, builder, {ty}, ops, std::nullopt,
3461 ty, loc);
3462 case NEON::BI__builtin_neon_vrndxh_f16: {
3464 mlir::Type halfTy = builder.getFp16Ty();
3465 return emitNeonCallToOp<cir::RintOp>(cgm, builder, {halfTy}, ops,
3466 std::nullopt, halfTy, loc);
3467 }
3468 case NEON::BI__builtin_neon_vrndx_v:
3469 case NEON::BI__builtin_neon_vrndxq_v:
3471 return emitNeonCallToOp<cir::RintOp>(cgm, builder, {ty}, ops, std::nullopt,
3472 ty, loc);
3473 case NEON::BI__builtin_neon_vrndh_f16: {
3475 mlir::Type halfTy = builder.getFp16Ty();
3476 return emitNeonCallToOp<cir::TruncOp>(cgm, builder, {halfTy}, ops,
3477 std::nullopt, halfTy, loc);
3478 }
3479 case NEON::BI__builtin_neon_vrnd_v:
3480 case NEON::BI__builtin_neon_vrndq_v:
3482 return emitNeonCallToOp<cir::TruncOp>(cgm, builder, {ty}, ops, std::nullopt,
3483 ty, loc);
3484 case NEON::BI__builtin_neon_vcvt_f64_v:
3485 case NEON::BI__builtin_neon_vcvtq_f64_v:
3486 ops[0] = builder.createBitcast(ops[0], ty);
3487 ty = getNeonType(
3488 this, NeonTypeFlags(NeonTypeFlags::Float64, false, type.isQuad()));
3489 return builder.createCast(loc, cir::CastKind::int_to_float, ops[0], ty);
3490 case NEON::BI__builtin_neon_vcvt_f64_f32: {
3491 auto v2f32 = cir::VectorType::get(cgm.floatTy, 2);
3492 auto v2f64 = cir::VectorType::get(cgm.doubleTy, 2);
3493 return builder.createFloatingCast(builder.createBitcast(ops[0], v2f32),
3494 v2f64);
3495 }
3496 case NEON::BI__builtin_neon_vcvt_f32_f64: {
3497 auto v2f32 = cir::VectorType::get(cgm.floatTy, 2);
3498 auto v2f64 = cir::VectorType::get(cgm.doubleTy, 2);
3499 return builder.createFloatingCast(builder.createBitcast(ops[0], v2f64),
3500 v2f32);
3501 }
3502 case NEON::BI__builtin_neon_vcvt_s32_v:
3503 case NEON::BI__builtin_neon_vcvt_u32_v:
3504 case NEON::BI__builtin_neon_vcvt_s64_v:
3505 case NEON::BI__builtin_neon_vcvt_u64_v:
3506 case NEON::BI__builtin_neon_vcvt_s16_f16:
3507 case NEON::BI__builtin_neon_vcvt_u16_f16:
3508 case NEON::BI__builtin_neon_vcvtq_s32_v:
3509 case NEON::BI__builtin_neon_vcvtq_u32_v:
3510 case NEON::BI__builtin_neon_vcvtq_s64_v:
3511 case NEON::BI__builtin_neon_vcvtq_u64_v:
3512 case NEON::BI__builtin_neon_vcvtq_s16_f16:
3513 case NEON::BI__builtin_neon_vcvtq_u16_f16:
3514
3515 case NEON::BI__builtin_neon_vcvta_s16_f16:
3516 case NEON::BI__builtin_neon_vcvta_u16_f16:
3517 case NEON::BI__builtin_neon_vcvtaq_s16_f16:
3518 case NEON::BI__builtin_neon_vcvtaq_u16_f16:
3519 cgm.errorNYI(expr->getSourceRange(),
3520 std::string("unimplemented AArch64 builtin call: ") +
3521 getContext().BuiltinInfo.getName(builtinID));
3522 return mlir::Value{};
3523 case NEON::BI__builtin_neon_vcvta_s32_v:
3524 case NEON::BI__builtin_neon_vcvtaq_s32_v:
3525 case NEON::BI__builtin_neon_vcvta_u32_v:
3526 case NEON::BI__builtin_neon_vcvtaq_u32_v:
3527 case NEON::BI__builtin_neon_vcvta_s64_v:
3528 case NEON::BI__builtin_neon_vcvtaq_s64_v:
3529 case NEON::BI__builtin_neon_vcvta_u64_v:
3530 case NEON::BI__builtin_neon_vcvtaq_u64_v: {
3531 auto argTy = getFloatNeonType(*this, type);
3532 llvm::StringRef intrName =
3533 usgn ? "aarch64.neon.fcvtau" : "aarch64.neon.fcvtas";
3534 return emitNeonCall(cgm, builder, {argTy}, ops, intrName, ty, loc);
3535 }
3536
3537 case NEON::BI__builtin_neon_vcvtm_s16_f16:
3538 case NEON::BI__builtin_neon_vcvtmq_s16_f16:
3539 case NEON::BI__builtin_neon_vcvtm_u16_f16:
3540 case NEON::BI__builtin_neon_vcvtmq_u16_f16:
3541 cgm.errorNYI(expr->getSourceRange(),
3542 std::string("unimplemented AArch64 builtin call: ") +
3543 getContext().BuiltinInfo.getName(builtinID));
3544 return mlir::Value{};
3545 case NEON::BI__builtin_neon_vcvtm_s32_v:
3546 case NEON::BI__builtin_neon_vcvtmq_s32_v:
3547 case NEON::BI__builtin_neon_vcvtm_u32_v:
3548 case NEON::BI__builtin_neon_vcvtmq_u32_v:
3549 case NEON::BI__builtin_neon_vcvtm_s64_v:
3550 case NEON::BI__builtin_neon_vcvtmq_s64_v:
3551 case NEON::BI__builtin_neon_vcvtm_u64_v:
3552 case NEON::BI__builtin_neon_vcvtmq_u64_v: {
3553 auto argTy = getFloatNeonType(*this, type);
3554 llvm::StringRef intrName =
3555 usgn ? "aarch64.neon.fcvtmu" : "aarch64.neon.fcvtms";
3556 return emitNeonCall(cgm, builder, {argTy}, ops, intrName, ty, loc);
3557 }
3558
3559 case NEON::BI__builtin_neon_vcvtn_s16_f16:
3560 case NEON::BI__builtin_neon_vcvtnq_s16_f16:
3561 case NEON::BI__builtin_neon_vcvtn_u16_f16:
3562 case NEON::BI__builtin_neon_vcvtnq_u16_f16:
3563 cgm.errorNYI(expr->getSourceRange(),
3564 std::string("unimplemented AArch64 builtin call: ") +
3565 getContext().BuiltinInfo.getName(builtinID));
3566 return mlir::Value{};
3567
3568 case NEON::BI__builtin_neon_vcvtn_s32_v:
3569 case NEON::BI__builtin_neon_vcvtnq_s32_v:
3570 case NEON::BI__builtin_neon_vcvtn_u32_v:
3571 case NEON::BI__builtin_neon_vcvtnq_u32_v:
3572 case NEON::BI__builtin_neon_vcvtn_s64_v:
3573 case NEON::BI__builtin_neon_vcvtnq_s64_v:
3574 case NEON::BI__builtin_neon_vcvtn_u64_v:
3575 case NEON::BI__builtin_neon_vcvtnq_u64_v: {
3576 auto argTy = getFloatNeonType(*this, type);
3577 llvm::StringRef intrName =
3578 usgn ? "aarch64.neon.fcvtnu" : "aarch64.neon.fcvtns";
3579 return emitNeonCall(cgm, builder, {argTy}, ops, intrName, ty, loc);
3580 }
3581
3582 case NEON::BI__builtin_neon_vcvtp_s16_f16:
3583 case NEON::BI__builtin_neon_vcvtpq_s16_f16:
3584 case NEON::BI__builtin_neon_vcvtp_u16_f16:
3585 case NEON::BI__builtin_neon_vcvtpq_u16_f16:
3586 cgm.errorNYI(expr->getSourceRange(),
3587 std::string("unimplemented AArch64 builtin call: ") +
3588 getContext().BuiltinInfo.getName(builtinID));
3589 return mlir::Value{};
3590 case NEON::BI__builtin_neon_vcvtp_s32_v:
3591 case NEON::BI__builtin_neon_vcvtpq_s32_v:
3592 case NEON::BI__builtin_neon_vcvtp_u32_v:
3593 case NEON::BI__builtin_neon_vcvtpq_u32_v:
3594 case NEON::BI__builtin_neon_vcvtp_s64_v:
3595 case NEON::BI__builtin_neon_vcvtpq_s64_v:
3596 case NEON::BI__builtin_neon_vcvtp_u64_v:
3597 case NEON::BI__builtin_neon_vcvtpq_u64_v: {
3598 auto argTy = getFloatNeonType(*this, type);
3599 llvm::StringRef intrName =
3600 usgn ? "aarch64.neon.fcvtpu" : "aarch64.neon.fcvtps";
3601 return emitNeonCall(cgm, builder, {argTy}, ops, intrName, ty, loc);
3602 }
3603
3604 case NEON::BI__builtin_neon_vmulx_v:
3605 case NEON::BI__builtin_neon_vmulxq_v:
3606 case NEON::BI__builtin_neon_vmulxh_lane_f16:
3607 case NEON::BI__builtin_neon_vmulxh_laneq_f16:
3608 case NEON::BI__builtin_neon_vmul_lane_v:
3609 case NEON::BI__builtin_neon_vmul_laneq_v:
3610 case NEON::BI__builtin_neon_vpmaxnm_v:
3611 case NEON::BI__builtin_neon_vpmaxnmq_v:
3612 cgm.errorNYI(expr->getSourceRange(),
3613 std::string("unimplemented AArch64 builtin call: ") +
3614 getContext().BuiltinInfo.getName(builtinID));
3615 return mlir::Value{};
3616 case NEON::BI__builtin_neon_vpminnm_v:
3617 case NEON::BI__builtin_neon_vpminnmq_v:
3618 intrName = "aarch64.neon.fminnmp";
3619 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3620 case NEON::BI__builtin_neon_vsqrth_f16: {
3621 mlir::Type halfTy = builder.getFp16Ty();
3622 return emitNeonCallToOp<cir::SqrtOp>(cgm, builder, {halfTy}, ops,
3623 std::nullopt, halfTy, loc);
3624 }
3625 case NEON::BI__builtin_neon_vsqrt_v:
3626 case NEON::BI__builtin_neon_vsqrtq_v:
3628 return emitNeonCallToOp<cir::SqrtOp>(cgm, builder, {ty}, ops, std::nullopt,
3629 ty, loc);
3630 case NEON::BI__builtin_neon_vrbit_v:
3631 case NEON::BI__builtin_neon_vrbitq_v:
3632 case NEON::BI__builtin_neon_vmaxv_f16:
3633 case NEON::BI__builtin_neon_vmaxvq_f16:
3634 case NEON::BI__builtin_neon_vminv_f16:
3635 case NEON::BI__builtin_neon_vminvq_f16:
3636 case NEON::BI__builtin_neon_vmaxnmv_f16:
3637 case NEON::BI__builtin_neon_vmaxnmvq_f16:
3638 case NEON::BI__builtin_neon_vminnmv_f16:
3639 case NEON::BI__builtin_neon_vminnmvq_f16:
3640 case NEON::BI__builtin_neon_vmul_n_f64:
3641 cgm.errorNYI(expr->getSourceRange(),
3642 std::string("unimplemented AArch64 builtin call: ") +
3643 getContext().BuiltinInfo.getName(builtinID));
3644 return mlir::Value{};
3645 case NEON::BI__builtin_neon_vaddlv_u8:
3646 case NEON::BI__builtin_neon_vaddlvq_u8:
3647 case NEON::BI__builtin_neon_vaddlv_u16:
3648 case NEON::BI__builtin_neon_vaddlvq_u16:
3649 case NEON::BI__builtin_neon_vaddlv_s8:
3650 case NEON::BI__builtin_neon_vaddlvq_s8:
3651 case NEON::BI__builtin_neon_vaddlv_s16:
3652 case NEON::BI__builtin_neon_vaddlvq_s16: {
3653 mlir::Type argTy = convertType(expr->getArg(0)->getType());
3654 mlir::Type userRetTy = convertType(expr->getType());
3655 auto eltTy = mlir::cast<cir::IntType>(
3656 mlir::cast<cir::VectorType>(argTy).getElementType());
3657 bool isUnsigned = !eltTy.isSigned();
3658 // These builtins only use 8 and 16-bit element vectors; the intrinsic
3659 // always produces i32. The C result is i32 for 16-bit elements, but i16
3660 // for 8-bit elements, so we emit at i32 and narrow only in that case.
3661 bool needsTrunc = eltTy.getWidth() == 8;
3662 intrName = isUnsigned ? "aarch64.neon.uaddlv" : "aarch64.neon.saddlv";
3663 mlir::Type intrRetTy = userRetTy;
3664 if (needsTrunc)
3665 intrRetTy = isUnsigned ? builder.getUInt32Ty() : builder.getSInt32Ty();
3666 mlir::Value result =
3667 emitNeonCall(cgm, builder, {argTy}, ops, intrName, intrRetTy, loc);
3668 if (needsTrunc)
3669 result = builder.createIntCast(result, userRetTy);
3670 return result;
3671 }
3672 case NEON::BI__builtin_neon_vsri_n_v:
3673 case NEON::BI__builtin_neon_vsriq_n_v: {
3675 ops[0], ops[1], builder.createIntCast(ops[2], builder.getUInt32Ty())};
3676 return emitNeonCall(cgm, builder, {ty, ty, builder.getUInt32Ty()}, vsriArgs,
3677 "aarch64.neon.vsri", ty, loc);
3678 }
3679 case NEON::BI__builtin_neon_vsli_n_v:
3680 case NEON::BI__builtin_neon_vsliq_n_v: {
3681
3682 intrName = "aarch64.neon.vsli";
3683
3684 llvm::SmallVector<mlir::Type> argTypes = {ty, ty, ops[2].getType()};
3685
3686 return emitNeonCall(cgm, builder, argTypes, ops, intrName, ty, loc,
3687 /*isConstrainedFPIntrinsic=*/false,
3688 /*shift=*/0, /*rightshift=*/false);
3689 }
3690 case NEON::BI__builtin_neon_vsra_n_v:
3691 case NEON::BI__builtin_neon_vsraq_n_v: {
3692 ops[0] = builder.createBitcast(ops[0], ty);
3693 ops[1] = emitNeonRShiftImm(*this, ops[1], ops[2], ty, usgn, loc);
3694 return builder.createAdd(loc, ops[0], ops[1]);
3695 }
3696 case NEON::BI__builtin_neon_vrsra_n_v:
3697 case NEON::BI__builtin_neon_vrsraq_n_v: {
3698 intrName = usgn ? "aarch64.neon.urshl" : "aarch64.neon.srshl";
3699 // The llvm intrinsic is expecting negative shift amount for right shift.
3700 // Thus we have to make shift amount vec type to be signed.
3701 cir::VectorType shiftAmtVecTy =
3702 usgn ? getSignChangedVectorType(builder, ty) : ty;
3703 llvm::SmallVector<mlir::Value, 2> tmpOps = {ops[1], ops[2]};
3704 mlir::Value tmp = emitNeonCall(cgm, builder, {ty, shiftAmtVecTy}, tmpOps,
3705 intrName, ty, loc,
3706 /*isConstrainedFPIntrinsic=*/false,
3707 /*shift=*/1, /*rightshift=*/true);
3708 ops[0] = builder.createBitcast(ops[0], ty);
3709 return builder.createAdd(loc, ops[0], tmp);
3710 }
3711 case NEON::BI__builtin_neon_vld1_v:
3712 case NEON::BI__builtin_neon_vld1q_v:
3713 return builder.createLoad(loc, ptrOp0.withElementType(builder, ty));
3714 case NEON::BI__builtin_neon_vst1_v:
3715 case NEON::BI__builtin_neon_vst1q_v: {
3716 ops[1] = builder.createBitcast(ops[1], ty);
3717 builder.createStore(loc, ops[1], ptrOp0.withElementType(builder, ty));
3718 return nullptr;
3719 }
3720 case NEON::BI__builtin_neon_vld1_lane_v:
3721 case NEON::BI__builtin_neon_vld1q_lane_v: {
3722 ops[1] = builder.createBitcast(ops[1], ty);
3723 mlir::Value scalar = builder.createLoad(
3724 loc, ptrOp0.withElementType(builder, ty.getElementType()));
3725 return cir::VecInsertOp::create(builder, loc, ops[1], scalar, ops[2]);
3726 }
3727 case NEON::BI__builtin_neon_vld1_dup_v:
3728 case NEON::BI__builtin_neon_vld1q_dup_v: {
3729 mlir::Value scalar = builder.createLoad(
3730 loc, ptrOp0.withElementType(builder, ty.getElementType()));
3731 return cir::VecSplatOp::create(builder, loc, ty, scalar);
3732 }
3733 case NEON::BI__builtin_neon_vldap1_lane_s64:
3734 case NEON::BI__builtin_neon_vldap1q_lane_s64:
3735 cgm.errorNYI(expr->getSourceRange(),
3736 std::string("unimplemented AArch64 builtin call: ") +
3737 getContext().BuiltinInfo.getName(builtinID));
3738 return mlir::Value{};
3739 case NEON::BI__builtin_neon_vst1_lane_v:
3740 case NEON::BI__builtin_neon_vst1q_lane_v: {
3741 ops[1] = builder.createBitcast(ops[1], ty);
3742 mlir::Value scalar = builder.createExtractElement(
3743 loc, ops[1], static_cast<uint64_t>(getIntValueFromConstOp(ops[2])));
3744 builder.createStore(loc, scalar,
3745 ptrOp0.withElementType(builder, scalar.getType()));
3746 return nullptr;
3747 }
3748 case NEON::BI__builtin_neon_vstl1_lane_s64:
3749 case NEON::BI__builtin_neon_vstl1q_lane_s64:
3750 cgm.errorNYI(expr->getSourceRange(),
3751 std::string("unimplemented AArch64 builtin call: ") +
3752 getContext().BuiltinInfo.getName(builtinID));
3753 return mlir::Value{};
3754 case NEON::BI__builtin_neon_vld2_v:
3755 case NEON::BI__builtin_neon_vld2q_v:
3756 return emitNeonMultiVecLoad(*this, ops, llvm::Intrinsic::aarch64_neon_ld2,
3757 ty, 2, loc);
3758 case NEON::BI__builtin_neon_vld3_v:
3759 case NEON::BI__builtin_neon_vld3q_v:
3760 return emitNeonMultiVecLoad(*this, ops, llvm::Intrinsic::aarch64_neon_ld3,
3761 ty, 3, loc);
3762 case NEON::BI__builtin_neon_vld4_v:
3763 case NEON::BI__builtin_neon_vld4q_v:
3764 return emitNeonMultiVecLoad(*this, ops, llvm::Intrinsic::aarch64_neon_ld4,
3765 ty, 4, loc);
3766 case NEON::BI__builtin_neon_vld2_dup_v:
3767 case NEON::BI__builtin_neon_vld2q_dup_v:
3768 return emitNeonMultiVecLoad(*this, ops, llvm::Intrinsic::aarch64_neon_ld2r,
3769 ty, 2, loc);
3770 case NEON::BI__builtin_neon_vld3_dup_v:
3771 case NEON::BI__builtin_neon_vld3q_dup_v:
3772 return emitNeonMultiVecLoad(*this, ops, llvm::Intrinsic::aarch64_neon_ld3r,
3773 ty, 3, loc);
3774 case NEON::BI__builtin_neon_vld4_dup_v:
3775 case NEON::BI__builtin_neon_vld4q_dup_v:
3776 return emitNeonMultiVecLoad(*this, ops, llvm::Intrinsic::aarch64_neon_ld4r,
3777 ty, 4, loc);
3778 case NEON::BI__builtin_neon_vld2_lane_v:
3779 case NEON::BI__builtin_neon_vld2q_lane_v:
3781 *this, ops, llvm::Intrinsic::aarch64_neon_ld2lane, ty, 2, loc);
3782 case NEON::BI__builtin_neon_vld3_lane_v:
3783 case NEON::BI__builtin_neon_vld3q_lane_v:
3785 *this, ops, llvm::Intrinsic::aarch64_neon_ld3lane, ty, 3, loc);
3786 case NEON::BI__builtin_neon_vld4_lane_v:
3787 case NEON::BI__builtin_neon_vld4q_lane_v:
3789 *this, ops, llvm::Intrinsic::aarch64_neon_ld4lane, ty, 4, loc);
3790 case NEON::BI__builtin_neon_vst2_v:
3791 case NEON::BI__builtin_neon_vst2q_v: {
3792 // The builtin call has the pointer first, but the AArch64 st2 intrinsic
3793 // takes the vector operands first and the pointer last.
3794 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3795 llvm::SmallVector<mlir::Type> argTypes = {ty, ty, builder.getVoidPtrTy()};
3796 return emitNeonCall(cgm, builder, argTypes, ops, "aarch64.neon.st2",
3797 cgm.voidTy, loc);
3798 }
3799 case NEON::BI__builtin_neon_vst2_lane_v:
3800 case NEON::BI__builtin_neon_vst2q_lane_v: {
3801 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3802 ops[2] = builder.createIntCast(ops[2], sInt64Ty);
3803 llvm::SmallVector<mlir::Type> argTypes = {ty, ty, sInt64Ty,
3804 builder.getVoidPtrTy()};
3805 return emitNeonCall(cgm, builder, argTypes, ops, "aarch64.neon.st2lane",
3806 cgm.voidTy, loc);
3807 }
3808 case NEON::BI__builtin_neon_vst3_v:
3809 case NEON::BI__builtin_neon_vst3q_v: {
3810 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3811 llvm::SmallVector<mlir::Type> argTypes = {ty, ty, ty,
3812 builder.getVoidPtrTy()};
3813 return emitNeonCall(cgm, builder, argTypes, ops, "aarch64.neon.st3",
3814 cgm.voidTy, loc);
3815 }
3816 case NEON::BI__builtin_neon_vst3_lane_v:
3817 case NEON::BI__builtin_neon_vst3q_lane_v: {
3818 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3819 ops[3] = builder.createIntCast(ops[3], sInt64Ty);
3820 llvm::SmallVector<mlir::Type> argTypes = {ty, ty, ty, sInt64Ty,
3821 builder.getVoidPtrTy()};
3822 return emitNeonCall(cgm, builder, argTypes, ops, "aarch64.neon.st3lane",
3823 cgm.voidTy, loc);
3824 }
3825 case NEON::BI__builtin_neon_vst4_v:
3826 case NEON::BI__builtin_neon_vst4q_v: {
3827 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3828 llvm::SmallVector<mlir::Type> argTypes = {ty, ty, ty, ty,
3829 builder.getVoidPtrTy()};
3830 return emitNeonCall(cgm, builder, argTypes, ops, "aarch64.neon.st4",
3831 cgm.voidTy, loc);
3832 }
3833 case NEON::BI__builtin_neon_vst4_lane_v:
3834 case NEON::BI__builtin_neon_vst4q_lane_v: {
3835 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3836 ops[4] = builder.createIntCast(ops[4], sInt64Ty);
3838 ty, ty, ty, ty, sInt64Ty, builder.getVoidPtrTy()};
3839 return emitNeonCall(cgm, builder, argTypes, ops, "aarch64.neon.st4lane",
3840 cgm.voidTy, loc);
3841 }
3842 case NEON::BI__builtin_neon_vtrn_v:
3843 case NEON::BI__builtin_neon_vtrnq_v: {
3844 ops[1] = builder.createBitcast(ops[1], ty);
3845 ops[2] = builder.createBitcast(ops[2], ty);
3846 // Adding a bitcast here as Ops[0] might be a void pointer.
3847 mlir::Value baseAddr =
3848 builder.createBitcast(ops[0], builder.getPointerTo(ty));
3849 mlir::Value sv;
3850
3851 for (unsigned vi = 0; vi != 2; ++vi) {
3853 for (unsigned i = 0, e = ty.getSize(); i != e; i += 2) {
3854 indices.push_back(i + vi);
3855 indices.push_back(i + e + vi);
3856 }
3857 cir::ConstantOp idx = builder.getConstInt(loc, builder.getSInt32Ty(), vi);
3858 mlir::Value addr = builder.createPtrStride(loc, baseAddr, idx);
3859 sv = builder.createVecShuffle(loc, ops[1], ops[2], indices);
3860 (void)builder.CIRBaseBuilderTy::createStore(loc, sv, addr);
3861 }
3862 return sv;
3863 }
3864 case NEON::BI__builtin_neon_vuzp_v:
3865 case NEON::BI__builtin_neon_vuzpq_v: {
3866 ops[1] = builder.createBitcast(ops[1], ty);
3867 ops[2] = builder.createBitcast(ops[2], ty);
3868 // Adding a bitcast here as Ops[0] might be a void pointer.
3869 mlir::Value baseAddr =
3870 builder.createBitcast(ops[0], builder.getPointerTo(ty));
3871 mlir::Value sv;
3872 for (unsigned vi = 0; vi != 2; ++vi) {
3874 for (unsigned i = 0, e = ty.getSize(); i != e; ++i) {
3875 indices.push_back(2 * i + vi);
3876 }
3877 cir::ConstantOp idx = builder.getConstInt(loc, builder.getSInt32Ty(), vi);
3878 mlir::Value addr = builder.createPtrStride(loc, baseAddr, idx);
3879 sv = builder.createVecShuffle(loc, ops[1], ops[2], indices);
3880 (void)builder.CIRBaseBuilderTy::createStore(loc, sv, addr);
3881 }
3882 return sv;
3883 }
3884 case NEON::BI__builtin_neon_vzip_v:
3885 case NEON::BI__builtin_neon_vzipq_v: {
3886 ops[1] = builder.createBitcast(ops[1], ty);
3887 ops[2] = builder.createBitcast(ops[2], ty);
3888 // Adding a bitcast here as Ops[0] might be a void pointer.
3889 mlir::Value baseAddr =
3890 builder.createBitcast(ops[0], builder.getPointerTo(ty));
3891 mlir::Value sv;
3892 for (unsigned vi = 0; vi != 2; ++vi) {
3894 for (unsigned i = 0, e = ty.getSize(); i != e; i += 2) {
3895 indices.push_back((i + vi * e) >> 1);
3896 indices.push_back(((i + vi * e) >> 1) + e);
3897 }
3898 cir::ConstantOp idx = builder.getConstInt(loc, builder.getSInt32Ty(), vi);
3899 mlir::Value addr = builder.createPtrStride(loc, baseAddr, idx);
3900 sv = builder.createVecShuffle(loc, ops[1], ops[2], indices);
3901 (void)builder.CIRBaseBuilderTy::createStore(loc, sv, addr);
3902 }
3903 return sv;
3904 }
3905 case NEON::BI__builtin_neon_vqtbl1q_v:
3906 case NEON::BI__builtin_neon_vqtbl2q_v:
3907 case NEON::BI__builtin_neon_vqtbl3q_v:
3908 case NEON::BI__builtin_neon_vqtbl4q_v:
3909 case NEON::BI__builtin_neon_vqtbx1q_v:
3910 case NEON::BI__builtin_neon_vqtbx2q_v:
3911 case NEON::BI__builtin_neon_vqtbx3q_v:
3912 case NEON::BI__builtin_neon_vqtbx4q_v:
3913 cgm.errorNYI(expr->getSourceRange(),
3914 std::string("unimplemented AArch64 builtin call: ") +
3915 getContext().BuiltinInfo.getName(builtinID));
3916 return mlir::Value{};
3917 case NEON::BI__builtin_neon_vsqadd_v:
3918 case NEON::BI__builtin_neon_vsqaddq_v:
3919 return emitNeonCall(cgm, builder, {ty, ty}, ops, "aarch64.neon.usqadd", ty,
3920 loc);
3921 case NEON::BI__builtin_neon_vuqadd_v:
3922 case NEON::BI__builtin_neon_vuqaddq_v:
3923 return emitNeonCall(cgm, builder, {ty, ty}, ops, "aarch64.neon.suqadd", ty,
3924 loc);
3925 case NEON::BI__builtin_neon_vluti2_laneq_mf8:
3926 case NEON::BI__builtin_neon_vluti2_laneq_bf16:
3927 case NEON::BI__builtin_neon_vluti2_laneq_f16:
3928 case NEON::BI__builtin_neon_vluti2_laneq_p16:
3929 case NEON::BI__builtin_neon_vluti2_laneq_p8:
3930 case NEON::BI__builtin_neon_vluti2_laneq_s16:
3931 case NEON::BI__builtin_neon_vluti2_laneq_s8:
3932 case NEON::BI__builtin_neon_vluti2_laneq_u16:
3933 case NEON::BI__builtin_neon_vluti2_laneq_u8:
3934 case NEON::BI__builtin_neon_vluti2q_laneq_mf8:
3935 case NEON::BI__builtin_neon_vluti2q_laneq_bf16:
3936 case NEON::BI__builtin_neon_vluti2q_laneq_f16:
3937 case NEON::BI__builtin_neon_vluti2q_laneq_p16:
3938 case NEON::BI__builtin_neon_vluti2q_laneq_p8:
3939 case NEON::BI__builtin_neon_vluti2q_laneq_s16:
3940 case NEON::BI__builtin_neon_vluti2q_laneq_s8:
3941 case NEON::BI__builtin_neon_vluti2q_laneq_u16:
3942 case NEON::BI__builtin_neon_vluti2q_laneq_u8:
3943 case NEON::BI__builtin_neon_vluti2_lane_mf8:
3944 case NEON::BI__builtin_neon_vluti2_lane_bf16:
3945 case NEON::BI__builtin_neon_vluti2_lane_f16:
3946 case NEON::BI__builtin_neon_vluti2_lane_p16:
3947 case NEON::BI__builtin_neon_vluti2_lane_p8:
3948 case NEON::BI__builtin_neon_vluti2_lane_s16:
3949 case NEON::BI__builtin_neon_vluti2_lane_s8:
3950 case NEON::BI__builtin_neon_vluti2_lane_u16:
3951 case NEON::BI__builtin_neon_vluti2_lane_u8:
3952 case NEON::BI__builtin_neon_vluti2q_lane_mf8:
3953 case NEON::BI__builtin_neon_vluti2q_lane_bf16:
3954 case NEON::BI__builtin_neon_vluti2q_lane_f16:
3955 case NEON::BI__builtin_neon_vluti2q_lane_p16:
3956 case NEON::BI__builtin_neon_vluti2q_lane_p8:
3957 case NEON::BI__builtin_neon_vluti2q_lane_s16:
3958 case NEON::BI__builtin_neon_vluti2q_lane_s8:
3959 case NEON::BI__builtin_neon_vluti2q_lane_u16:
3960 case NEON::BI__builtin_neon_vluti2q_lane_u8:
3961 case NEON::BI__builtin_neon_vluti4q_lane_mf8:
3962 case NEON::BI__builtin_neon_vluti4q_lane_p8:
3963 case NEON::BI__builtin_neon_vluti4q_lane_s8:
3964 case NEON::BI__builtin_neon_vluti4q_lane_u8:
3965 case NEON::BI__builtin_neon_vluti4q_laneq_mf8:
3966 case NEON::BI__builtin_neon_vluti4q_laneq_p8:
3967 case NEON::BI__builtin_neon_vluti4q_laneq_s8:
3968 case NEON::BI__builtin_neon_vluti4q_laneq_u8:
3969 case NEON::BI__builtin_neon_vluti4q_lane_bf16_x2:
3970 case NEON::BI__builtin_neon_vluti4q_lane_f16_x2:
3971 case NEON::BI__builtin_neon_vluti4q_lane_p16_x2:
3972 case NEON::BI__builtin_neon_vluti4q_lane_s16_x2:
3973 case NEON::BI__builtin_neon_vluti4q_lane_u16_x2:
3974 case NEON::BI__builtin_neon_vluti4q_laneq_bf16_x2:
3975 case NEON::BI__builtin_neon_vluti4q_laneq_f16_x2:
3976 case NEON::BI__builtin_neon_vluti4q_laneq_p16_x2:
3977 case NEON::BI__builtin_neon_vluti4q_laneq_s16_x2:
3978 case NEON::BI__builtin_neon_vluti4q_laneq_u16_x2:
3979 case NEON::BI__builtin_neon_vmmlaq_f16_mf8_fpm:
3980 case NEON::BI__builtin_neon_vmmlaq_f32_mf8_fpm:
3981 case NEON::BI__builtin_neon_vcvt1_low_bf16_mf8_fpm:
3982 case NEON::BI__builtin_neon_vcvt1_bf16_mf8_fpm:
3983 case NEON::BI__builtin_neon_vcvt1_high_bf16_mf8_fpm:
3984 case NEON::BI__builtin_neon_vcvt2_low_bf16_mf8_fpm:
3985 case NEON::BI__builtin_neon_vcvt2_bf16_mf8_fpm:
3986 case NEON::BI__builtin_neon_vcvt2_high_bf16_mf8_fpm:
3987 case NEON::BI__builtin_neon_vcvt1_low_f16_mf8_fpm:
3988 case NEON::BI__builtin_neon_vcvt1_f16_mf8_fpm:
3989 case NEON::BI__builtin_neon_vcvt1_high_f16_mf8_fpm:
3990 case NEON::BI__builtin_neon_vcvt2_low_f16_mf8_fpm:
3991 case NEON::BI__builtin_neon_vcvt2_f16_mf8_fpm:
3992 case NEON::BI__builtin_neon_vcvt2_high_f16_mf8_fpm:
3993 case NEON::BI__builtin_neon_vcvt_mf8_f32_fpm:
3994 case NEON::BI__builtin_neon_vcvt_mf8_f16_fpm:
3995 case NEON::BI__builtin_neon_vcvtq_mf8_f16_fpm:
3996 case NEON::BI__builtin_neon_vcvt_high_mf8_f32_fpm:
3997 case NEON::BI__builtin_neon_vdot_f16_mf8_fpm:
3998 case NEON::BI__builtin_neon_vdotq_f16_mf8_fpm:
3999 case NEON::BI__builtin_neon_vdot_lane_f16_mf8_fpm:
4000 case NEON::BI__builtin_neon_vdotq_lane_f16_mf8_fpm:
4001 case NEON::BI__builtin_neon_vdot_laneq_f16_mf8_fpm:
4002 case NEON::BI__builtin_neon_vdotq_laneq_f16_mf8_fpm:
4003 case NEON::BI__builtin_neon_vdot_f32_mf8_fpm:
4004 case NEON::BI__builtin_neon_vdotq_f32_mf8_fpm:
4005 case NEON::BI__builtin_neon_vdot_lane_f32_mf8_fpm:
4006 case NEON::BI__builtin_neon_vdotq_lane_f32_mf8_fpm:
4007 case NEON::BI__builtin_neon_vdot_laneq_f32_mf8_fpm:
4008 case NEON::BI__builtin_neon_vdotq_laneq_f32_mf8_fpm:
4009 case NEON::BI__builtin_neon_vmlalbq_f16_mf8_fpm:
4010 case NEON::BI__builtin_neon_vmlaltq_f16_mf8_fpm:
4011 case NEON::BI__builtin_neon_vmlallbbq_f32_mf8_fpm:
4012 case NEON::BI__builtin_neon_vmlallbtq_f32_mf8_fpm:
4013 case NEON::BI__builtin_neon_vmlalltbq_f32_mf8_fpm:
4014 case NEON::BI__builtin_neon_vmlallttq_f32_mf8_fpm:
4015 case NEON::BI__builtin_neon_vmlalbq_lane_f16_mf8_fpm:
4016 case NEON::BI__builtin_neon_vmlalbq_laneq_f16_mf8_fpm:
4017 case NEON::BI__builtin_neon_vmlaltq_lane_f16_mf8_fpm:
4018 case NEON::BI__builtin_neon_vmlaltq_laneq_f16_mf8_fpm:
4019 case NEON::BI__builtin_neon_vmlallbbq_lane_f32_mf8_fpm:
4020 case NEON::BI__builtin_neon_vmlallbbq_laneq_f32_mf8_fpm:
4021 case NEON::BI__builtin_neon_vmlallbtq_lane_f32_mf8_fpm:
4022 case NEON::BI__builtin_neon_vmlallbtq_laneq_f32_mf8_fpm:
4023 case NEON::BI__builtin_neon_vmlalltbq_lane_f32_mf8_fpm:
4024 case NEON::BI__builtin_neon_vmlalltbq_laneq_f32_mf8_fpm:
4025 case NEON::BI__builtin_neon_vmlallttq_lane_f32_mf8_fpm:
4026 case NEON::BI__builtin_neon_vmlallttq_laneq_f32_mf8_fpm:
4027 case NEON::BI__builtin_neon_vamin_f16:
4028 case NEON::BI__builtin_neon_vaminq_f16:
4029 case NEON::BI__builtin_neon_vamin_f32:
4030 case NEON::BI__builtin_neon_vaminq_f32:
4031 case NEON::BI__builtin_neon_vaminq_f64:
4032 case NEON::BI__builtin_neon_vamax_f16:
4033 case NEON::BI__builtin_neon_vamaxq_f16:
4034 case NEON::BI__builtin_neon_vamax_f32:
4035 case NEON::BI__builtin_neon_vamaxq_f32:
4036 case NEON::BI__builtin_neon_vamaxq_f64:
4037 case NEON::BI__builtin_neon_vscale_f16:
4038 case NEON::BI__builtin_neon_vscaleq_f16:
4039 case NEON::BI__builtin_neon_vscale_f32:
4040 case NEON::BI__builtin_neon_vscaleq_f32:
4041 case NEON::BI__builtin_neon_vscaleq_f64:
4042 cgm.errorNYI(expr->getSourceRange(),
4043 std::string("unimplemented AArch64 builtin call: ") +
4044 getContext().BuiltinInfo.getName(builtinID));
4045 return mlir::Value{};
4046 }
4047
4048 // Unreachable: All cases in the switch above return.
4049}
Utilities used for generating code for AArch64 that are shared between the classic and ClangIR code-g...
static bool isUnsigned(SValBuilder &SVB, NonLoc Value)
Defines enum values for all the target-independent builtin functions.
static std::pair< mlir::Type, llvm::SmallVector< mlir::Type > > deriveNeonSISDIntrinsicOperandTypes(CIRGenFunction &cgf, unsigned modifier, mlir::Type arg0Ty, mlir::Type resultTy, llvm::ArrayRef< mlir::Value > ops, unsigned iceArguments)
static bool hasExtraNeonArgument(unsigned builtinID)
Return true if BuiltinID is an overloaded Neon intrinsic with an extra argument that specifies the ve...
static bool aarch64SVEIntrinsicsProvenSorted
static const std::pair< unsigned, unsigned > neonEquivalentIntrinsicMap[]
static mlir::Value emitNeonSplat(CIRGenBuilderTy &builder, mlir::Location loc, mlir::Value v, mlir::Value lane, unsigned int resEltCnt)
static mlir::Value emitNeonCallToOp(CIRGenModule &cgm, CIRGenBuilderTy &builder, llvm::SmallVector< mlir::Type > argTypes, llvm::SmallVectorImpl< mlir::Value > &args, std::optional< llvm::StringRef > intrinsicName, mlir::Type funcResTy, mlir::Location loc, bool isConstrainedFPIntrinsic=false, unsigned shift=0, bool rightshift=false)
static cir::VectorType getSVEVectorForElementType(CIRGenModule &cgm, mlir::Type eltTy)
static cir::RecordType getNeonMultiVecTy(CIRGenBuilderTy &builder, mlir::Type vecTy, unsigned numVecs)
Return the anonymous record type {vecTy, ..., vecTy} (numVecs members) modelling the struct returned ...
static unsigned getSVEMinEltCount(clang::SVETypeFlags::EltType sveType)
static mlir::Value genVscaleTimesFactor(mlir::Location loc, CIRGenBuilderTy builder, mlir::Type cirTy, int32_t scalingFactor)
static cir::VectorType getFloatNeonType(CIRGenFunction &cgf, NeonTypeFlags intTypeFlags)
static llvm::StringRef getLLVMIntrNameNoPrefix(llvm::Intrinsic::ID intrID)
static mlir::Value emitNeonMultiVecLoadCall(CIRGenFunction &cgf, mlir::Value dest, llvm::SmallVector< mlir::Type > argTypes, llvm::SmallVectorImpl< mlir::Value > &args, llvm::Intrinsic::ID llvmIntrinsic, mlir::Type ty, unsigned numVecs, mlir::Location loc)
Call the multi-vector NEON load intrinsic llvmIntrinsic with args of argTypes and store the resulting...
static int64_t getIntValueFromConstOp(mlir::Value val)
static cir::VectorType deriveNeonBinaryArgType(CIRGenBuilderTy &builder, unsigned modifier, cir::VectorType vTy)
static const AArch64SVEAndSMEVectorIntrinsicInfo aarch64SVEIntrinsicMap[]
static mlir::Value emitCommonNeonBuiltinExpr(CIRGenFunction &cgf, unsigned builtinID, unsigned llvmIntrinsic, unsigned altLLVMIntrinsic, const char *nameHint, unsigned modifier, const CallExpr *expr, llvm::SmallVectorImpl< mlir::Value > &ops)
static mlir::Value emitNeonCall(CIRGenModule &cgm, CIRGenBuilderTy &builder, llvm::SmallVector< mlir::Type > argTypes, llvm::SmallVectorImpl< mlir::Value > &args, llvm::StringRef intrinsicName, mlir::Type funcResTy, mlir::Location loc, bool isConstrainedFPIntrinsic=false, unsigned shift=0, bool rightshift=false)
static unsigned getNeonMultiVecCount(unsigned builtinID)
The vld1_xN builtins move their data through an aggregate of N vectors.
static mlir::Value emitCommonNeonSISDBuiltinExpr(CIRGenFunction &cgf, const ARMNeonVectorIntrinsicInfo &info, llvm::SmallVectorImpl< mlir::Value > &ops, const CallExpr *expr, unsigned iceArguments)
static cir::VectorType getSignChangedVectorType(CIRGenBuilderTy &builder, cir::VectorType vecTy)
Flip the signedness of vecTy's element type, keeping the width and number of lanes the same.
static cir::VectorType getNeonType(CIRGenFunction *cgf, NeonTypeFlags typeFlags, bool hasLegalHalfType=true, bool v1Ty=false, bool allowBFloatArgsAndRet=true)
static cir::VectorType getNeonPairwiseWidenInputType(cir::VectorType resType, bool usgn)
static mlir::Value emitCommonNeonShift(CIRGenBuilderTy &builder, mlir::Location loc, cir::VectorType resTy, mlir::Value shifTgt, mlir::Value shiftAmt, bool shiftLeft)
static bool aarch64SIMDIntrinsicsProvenSorted
static cir::VectorType getIntVecFromVecTy(CIRGenBuilderTy &builder, cir::VectorType vecTy)
constexpr unsigned sveBitsPerBlock
static mlir::Value emitNeonMultiVecLoadLane(CIRGenFunction &cgf, llvm::ArrayRef< mlir::Value > ops, llvm::Intrinsic::ID llvmIntrinsic, mlir::Type ty, unsigned numVecs, mlir::Location loc)
Emit a multi-vector NEON load-lane: call llvmIntrinsic on the numVecs vector operands,...
static mlir::Value emitNeonMultiVecLoad(CIRGenFunction &cgf, llvm::ArrayRef< mlir::Value > ops, unsigned llvmIntrinsic, mlir::Type ty, unsigned numVecs, mlir::Location loc)
Emit a multi-vector NEON load: call llvmIntrinsic on the source pointer ops[1] and store the resultin...
static void vecExtendIntValue(CIRGenFunction &cgf, cir::VectorType argVTy, mlir::Value &arg, mlir::Location loc)
Create a vector from an input scalar argument, usually for a NEON SISD intrinsic call.
static mlir::Value emitNeonShiftVector(CIRGenBuilderTy &builder, mlir::Value shiftVal, cir::VectorType vecTy, mlir::Location loc, bool neg)
Build a constant shift amount vector of vecTy to shift a vector Here shiftVal is a constant integer t...
static const IntrinsicInfo * findARMVectorIntrinsicInMap(ArrayRef< IntrinsicInfo > intrinsicMap, unsigned builtinID, bool &mapProvenSorted)
static mlir::Value emitAArch64CompareBuiltinExpr(CIRGenFunction &cgf, CIRGenBuilderTy &builder, mlir::Location loc, mlir::Value src, mlir::Type retTy, const cir::CmpOpKind kind)
static mlir::Value emitNeonRShiftImm(CIRGenFunction &cgf, mlir::Value shiftVec, mlir::Value shiftVal, cir::VectorType vecTy, bool usgn, mlir::Location loc)
static bool aarch64SISDIntrinsicsProvenSorted
TokenType getType() const
Returns the token's type, e.g.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
Enumerates target-specific builtins in their own namespaces within namespace clang.
mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob=OverflowBehavior::None)
cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc)
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr)
mlir::Value createCast(mlir::Location loc, cir::CastKind kind, mlir::Value src, mlir::Type newTy)
mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob=OverflowBehavior::None)
mlir::Value createNUWAMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy)
cir::VecCmpOp createVecCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
mlir::Value createIntCast(mlir::Value src, mlir::Type newTy)
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty, int64_t value)
cir::PointerType getVoidPtrTy(clang::LangAS langAS=clang::LangAS::Default)
mlir::Value createShiftRight(mlir::Location loc, mlir::Value lhs, unsigned bits)
mlir::Value createXor(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
llvm::Align getABITypeAlign(mlir::Type ty) const
llvm::TypeSize getTypeSizeInBits(mlir::Type ty) const
C++ view class that accepts both !cir.struct and !cir.union types.
Definition CIRTypes.h:149
static llvm::SmallVector< RecordMemberKind > getAllDataKinds(llvm::ArrayRef< mlir::Type > members)
One Data kind per member.
Definition CIRTypes.cpp:162
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:239
Builtin::Context & BuiltinInfo
Definition ASTContext.h:848
QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error, unsigned *IntegerConstantArgs=nullptr) const
Return the type for the specified builtin.
@ GE_None
No error.
std::string getName(unsigned ID) const
Return the identifier name for the specified builtin, e.g.
Definition Builtins.cpp:94
mlir::Value getPointer() const
Definition Address.h:98
static Address invalid()
Definition Address.h:76
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const
Return address with different element type, a bitcast pointer, and the same alignment.
cir::ConstantOp getUInt64(uint64_t c, mlir::Location loc)
mlir::Value emitIntrinsicCallOp(mlir::Location loc, const llvm::StringRef str, const mlir::Type &resTy, Operands &&...op)
cir::IntType getSIntNTy(int n)
cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1, mlir::Value vec2, llvm::ArrayRef< mlir::Attribute > maskAttrs)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, bool isNontemporal=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
cir::ConstantOp getZero(mlir::Location loc, mlir::Type ty)
cir::StructType getAnonRecordTy(llvm::ArrayRef< mlir::Type > members, bool packed, llvm::ArrayRef< cir::RecordMemberKind > memberKinds)
Get a CIR anonymous struct type.
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
cir::VectorType getExtendedOrTruncatedElementVectorType(cir::VectorType vt, bool isExtended, bool isSigned=false)
cir::IntType getUIntNTy(int n)
mlir::Type convertType(clang::QualType t)
Address emitPointerWithAlignment(const clang::Expr *expr, LValueBaseInfo *baseInfo=nullptr)
Given an expression with a pointer type, emit the value and compute our best estimate of the alignmen...
const TargetInfo & getTarget() const
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
static int64_t getZExtIntValueFromConstOp(mlir::Value val)
Get zero-extended integer from a mlir::Value that is an int constant or a constant op.
mlir::Value emitSVEPredicateCast(mlir::Value pred, unsigned minNumElts, mlir::Location loc)
bool getAArch64SVEProcessedOperands(unsigned builtinID, const CallExpr *expr, SmallVectorImpl< mlir::Value > &ops, clang::SVETypeFlags typeFlags)
Address returnValue
The temporary alloca to hold the return value.
std::optional< mlir::Value > emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr, ReturnValueSlot returnValue, llvm::Triple::ArchType arch)
std::optional< mlir::Value > emitAArch64SMEBuiltinExpr(unsigned builtinID, const CallExpr *expr)
mlir::Value emitScalarExpr(const clang::Expr *e, bool ignoreResultAssign=false)
Emit the computation of the specified expression of scalar type.
CIRGenBuilderTy & getBuilder()
cir::VectorType getSVEType(const SVETypeFlags &typeFlags)
clang::ASTContext & getContext() const
std::optional< mlir::Value > emitAArch64SVEBuiltinExpr(unsigned builtinID, const CallExpr *expr)
mlir::Value emitScalarOrConstFoldImmArg(unsigned iceArguments, unsigned idx, const Expr *argExpr)
This class organizes the cross-function state that is used while generating CIR code.
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
const cir::CIRDataLayout getDataLayout() const
Contains the address where the return value of a function can be stored, and whether the address is v...
Definition CIRGenCall.h:260
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2987
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
This represents one expression.
Definition Expr.h:113
Flags to identify the types for overloaded Neon builtins.
EltType getEltType() const
Flags to identify the types for overloaded SVE builtins.
bool isReverseUSDOT() const
bool isGatherLoad() const
EltType getEltType() const
bool isPrefetch() const
bool isTupleSet() const
bool isReverseMergeAnyAccOp() const
bool isTupleGet() const
bool isInsertOp1SVALL() const
bool isAppendSVALL() const
bool isReverseMergeAnyBinOp() const
bool isStructStore() const
bool isTupleCreate() const
bool isGatherPrefetch() const
bool hasSplatOperand() const
MergeType getMergeType() const
bool isStructLoad() const
unsigned getSplatOperand() const
bool isScatterStore() const
bool isReverseCompare() const
virtual bool hasFastHalfType() const
Determine whether the target has fast native support for operations on half types.
Definition TargetInfo.h:705
Op::Properties getDefaultProperties(mlir::MLIRContext *context)
The properties of Op with every ODS-declared default applied.
Definition CIRDialect.h:88
const ARMNeonVectorIntrinsicInfo AArch64SISDIntrinsicMap[]
const ARMNeonVectorIntrinsicInfo AArch64SIMDIntrinsicMap[]
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
U cast(CodeGen::Address addr)
Definition Address.h:327
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
static bool msvcBuiltins()
static bool handleBuiltinICEArguments()
static bool aarch64SIMDIntrinsics()
static bool aarch64SVEIntrinsics()
static bool emitConstrainedFPCall()
static bool aarch64SMEIntrinsics()
static bool aarch64TblBuiltinExpr()
Describes an AArch64 SVE or SME intrinsic.
Describes an ARM or AArch64 NEON intrinsic, or an AArch64 SISD intrinsic.