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