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