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::getFixed(cgf.fP16Ty, (4ULL << isQuad));
101 return cir::VectorType::getFixed(cgf.floatTy, (2ULL << isQuad));
103 return cir::VectorType::getFixed(cgf.doubleTy, (1ULL << 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.getFixedSize();
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::getFixed(
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::getFixed(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).isScalable() &&
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::getFixed(typeFlags.isUnsigned() ? cgf->uInt8Ty
665 : cgf->sInt8Ty,
666 v1Ty ? 1 : (8 << isQuad));
668 return cir::VectorType::getFixed(cgf->uInt8Ty, v1Ty ? 1 : (8 << isQuad));
671 return cir::VectorType::getFixed(typeFlags.isUnsigned() ? cgf->uInt16Ty
672 : cgf->sInt16Ty,
673 v1Ty ? 1 : (4 << isQuad));
675 if (allowBFloatArgsAndRet)
676 return cir::VectorType::getFixed(cgf->getCIRGenModule().bFloat16Ty,
677 v1Ty ? 1 : (4 << isQuad));
678 return cir::VectorType::getFixed(cgf->uInt16Ty, v1Ty ? 1 : (4 << isQuad));
680 if (hasLegalHalfType)
681 return cir::VectorType::getFixed(cgf->getCIRGenModule().fP16Ty,
682 v1Ty ? 1 : (4 << isQuad));
683 return cir::VectorType::getFixed(cgf->uInt16Ty, v1Ty ? 1 : (4 << isQuad));
685 return cir::VectorType::getFixed(typeFlags.isUnsigned() ? cgf->uInt32Ty
686 : cgf->sInt32Ty,
687 v1Ty ? 1 : (2 << isQuad));
690 return cir::VectorType::getFixed(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::getFixed(cgf->uInt8Ty, 16);
699 return cir::VectorType::getFixed(cgf->getCIRGenModule().floatTy,
700 v1Ty ? 1 : (2 << isQuad));
702 return cir::VectorType::getFixed(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.getFixedSize();
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::getFixed(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::getFixed(cgf.cgm.doubleTy, 2);
1148 auto v2f32 = cir::VectorType::getFixed(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::getScalable(builder.getUIntNTy(1), minNumElts);
1515 if (pred.getType() == retTy)
1516 return pred;
1517
1518 llvm::Intrinsic::ID intID;
1519 switch (minNumElts) {
1520 default:
1521 llvm_unreachable("unsupported element count!");
1522 case 1:
1523 case 2:
1524 case 4:
1525 case 8:
1526 intID = Intrinsic::aarch64_sve_convert_from_svbool;
1527 break;
1528 case 16:
1529 intID = Intrinsic::aarch64_sve_convert_to_svbool;
1530 break;
1531 }
1532
1533 llvm::StringRef llvmIntrName = getLLVMIntrNameNoPrefix(intID);
1534 auto call = builder.emitIntrinsicCallOp(loc, llvmIntrName, retTy,
1535 mlir::ValueRange{pred});
1536 assert(call.getType() == retTy && "Unexpected return type!");
1537 return call;
1538}
1539
1540//===----------------------------------------------------------------------===//
1541// SVE helpers
1542//===----------------------------------------------------------------------===//
1543// Get the minimum number of elements in an SVE vector for the given element
1544// type. The actual number of elements in the vector would be an integer (power
1545// of two) multiple of this value.
1547 switch (sveType) {
1548 default:
1549 llvm_unreachable("Invalid SVETypeFlag!");
1550
1551 case SVETypeFlags::EltTyInt8:
1552 return 16;
1553 case SVETypeFlags::EltTyInt16:
1554 return 8;
1555 case SVETypeFlags::EltTyInt32:
1556 return 4;
1557 case SVETypeFlags::EltTyInt64:
1558 return 2;
1559
1560 case SVETypeFlags::EltTyMFloat8:
1561 return 16;
1562 case SVETypeFlags::EltTyFloat16:
1563 case SVETypeFlags::EltTyBFloat16:
1564 return 8;
1565 case SVETypeFlags::EltTyFloat32:
1566 return 4;
1567 case SVETypeFlags::EltTyFloat64:
1568 return 2;
1569
1570 case SVETypeFlags::EltTyBool8:
1571 return 16;
1572 case SVETypeFlags::EltTyBool16:
1573 return 8;
1574 case SVETypeFlags::EltTyBool32:
1575 return 4;
1576 case SVETypeFlags::EltTyBool64:
1577 return 2;
1578 }
1579}
1580
1581cir::VectorType CIRGenFunction::getSVEType(const SVETypeFlags &typeFlags) {
1582 switch (typeFlags.getEltType()) {
1583 default:
1584 llvm_unreachable("Invalid SVETypeFlag!");
1585
1586 case SVETypeFlags::EltTyInt8:
1587 return cir::VectorType::getScalable(builder.getUInt8Ty(), 16);
1588 case SVETypeFlags::EltTyInt16:
1589 return cir::VectorType::getScalable(builder.getUInt16Ty(), 8);
1590 case SVETypeFlags::EltTyInt32:
1591 return cir::VectorType::getScalable(builder.getUInt32Ty(), 4);
1592 case SVETypeFlags::EltTyInt64:
1593 return cir::VectorType::getScalable(builder.getUInt64Ty(), 2);
1594
1595 case SVETypeFlags::EltTyMFloat8:
1596 return cir::VectorType::getScalable(builder.getUInt8Ty(), 16);
1597 case SVETypeFlags::EltTyFloat16:
1598 return cir::VectorType::getScalable(builder.getFp16Ty(), 8);
1599 case SVETypeFlags::EltTyBFloat16:
1600 return cir::VectorType::getScalable(builder.getBfloat16Ty(), 8);
1601 case SVETypeFlags::EltTyFloat32:
1602 return cir::VectorType::getScalable(builder.getSingleTy(), 4);
1603 case SVETypeFlags::EltTyFloat64:
1604 return cir::VectorType::getScalable(builder.getDoubleTy(), 2);
1605
1606 case SVETypeFlags::EltTyBool8:
1607 return cir::VectorType::getScalable(builder.getUIntNTy(1), 16);
1608 case SVETypeFlags::EltTyBool16:
1609 return cir::VectorType::getScalable(builder.getUIntNTy(1), 8);
1610 case SVETypeFlags::EltTyBool32:
1611 return cir::VectorType::getScalable(builder.getUIntNTy(1), 4);
1612 case SVETypeFlags::EltTyBool64:
1613 return cir::VectorType::getScalable(builder.getUIntNTy(1), 2);
1614 }
1615}
1616
1617// TODO(cir): Share with OGCG
1618constexpr unsigned sveBitsPerBlock = 128;
1619
1620static cir::VectorType getSVEVectorForElementType(CIRGenModule &cgm,
1621 mlir::Type eltTy) {
1622 unsigned numElts =
1624 return cir::VectorType::getScalable(eltTy, numElts);
1625}
1626
1627//===----------------------------------------------------------------------===//
1628// SVE helpers
1629//===----------------------------------------------------------------------===//
1630std::optional<mlir::Value>
1632 const CallExpr *expr) {
1633 mlir::Type ty = convertType(expr->getType());
1634
1635 if (builtinID >= SVE::BI__builtin_sve_reinterpret_s8_s8 &&
1636 builtinID <= SVE::BI__builtin_sve_reinterpret_f64_f64_x4) {
1637 cgm.errorNYI(expr->getSourceRange(),
1638 std::string("unimplemented AArch64 builtin call: ") +
1639 getContext().BuiltinInfo.getName(builtinID));
1640 return mlir::Value{};
1641 }
1642
1644
1645 auto *builtinIntrInfo =
1648
1649 // The operands of the builtin call
1651
1652 SVETypeFlags typeFlags(builtinIntrInfo->TypeModifier);
1654 typeFlags))
1655 return mlir::Value{};
1656
1657 if (typeFlags.isLoad() || typeFlags.isStore() || typeFlags.isGatherLoad() ||
1658 typeFlags.isScatterStore() || typeFlags.isPrefetch() ||
1659 typeFlags.isGatherPrefetch() || typeFlags.isStructLoad() ||
1660 typeFlags.isStructStore() || typeFlags.isTupleSet() ||
1661 typeFlags.isTupleGet() || typeFlags.isTupleCreate() ||
1662 typeFlags.isUndef())
1663 cgm.errorNYI(expr->getSourceRange(),
1664 std::string("unimplemented AArch64 builtin call: ") +
1665 getContext().BuiltinInfo.getName(builtinID));
1666
1667 mlir::Location loc = getLoc(expr->getExprLoc());
1668
1669 // Handle built-ins for which there is a corresponding LLVM Intrinsic.
1670 // -------------------------------------------------------------------
1671 if (builtinIntrInfo->LLVMIntrinsic != 0) {
1672 // Emit set FPMR for intrinsics that require it.
1673 if (typeFlags.setsFPMR())
1674 cgm.errorNYI(expr->getSourceRange(),
1675 std::string("unimplemented AArch64 builtin call: ") +
1676 getContext().BuiltinInfo.getName(builtinID));
1677
1678 // Zero-ing predication
1679 if (typeFlags.getMergeType() == SVETypeFlags::MergeZeroExp) {
1680 auto null = builder.getNullValue(convertType(expr->getType()),
1681 getLoc(expr->getExprLoc()));
1682 ops.insert(ops.begin(), null);
1683 }
1684
1685 if (typeFlags.getMergeType() == SVETypeFlags::MergeAnyExp)
1686 ops.insert(ops.begin(),
1687 builder.getConstant(loc, cir::UndefAttr::get(ty)));
1688
1689 // Some ACLE builtins leave out the argument to specify the predicate
1690 // pattern, which is expected to be expanded to an SV_ALL pattern.
1691 if (typeFlags.isAppendSVALL())
1692 cgm.errorNYI(expr->getSourceRange(),
1693 std::string("unimplemented AArch64 builtin call: ") +
1694 getContext().BuiltinInfo.getName(builtinID));
1695 if (typeFlags.isInsertOp1SVALL())
1696 cgm.errorNYI(expr->getSourceRange(),
1697 std::string("unimplemented AArch64 builtin call: ") +
1698 getContext().BuiltinInfo.getName(builtinID));
1699
1700 // Predicates must match the main datatype.
1701 for (mlir::Value &op : ops)
1702 if (auto predTy = dyn_cast<cir::VectorType>(op.getType()))
1703 if (auto cirInt = dyn_cast<cir::IntType>(predTy.getElementType()))
1704 if (cirInt.getWidth() == 1)
1706 op, getSVEMinEltCount(typeFlags.getEltType()), loc);
1707
1708 // Splat scalar operand to vector (intrinsics with _n infix)
1709 if (typeFlags.hasSplatOperand()) {
1710 unsigned opNo = typeFlags.getSplatOperand();
1711 ops[opNo] = cir::VecSplatOp::create(
1712 builder, loc, getSVEVectorForElementType(cgm, ops[opNo].getType()),
1713 ops[opNo]);
1714 }
1715
1716 if (typeFlags.isReverseCompare())
1717 cgm.errorNYI(expr->getSourceRange(),
1718 std::string("unimplemented AArch64 builtin call: ") +
1719 getContext().BuiltinInfo.getName(builtinID));
1720 if (typeFlags.isReverseUSDOT())
1721 cgm.errorNYI(expr->getSourceRange(),
1722 std::string("unimplemented AArch64 builtin call: ") +
1723 getContext().BuiltinInfo.getName(builtinID));
1724 if (typeFlags.isReverseMergeAnyBinOp() &&
1725 typeFlags.getMergeType() == SVETypeFlags::MergeAny)
1726 cgm.errorNYI(expr->getSourceRange(),
1727 std::string("unimplemented AArch64 builtin call: ") +
1728 getContext().BuiltinInfo.getName(builtinID));
1729 if (typeFlags.isReverseMergeAnyAccOp() &&
1730 typeFlags.getMergeType() == SVETypeFlags::MergeAny)
1731 cgm.errorNYI(expr->getSourceRange(),
1732 std::string("unimplemented AArch64 builtin call: ") +
1733 getContext().BuiltinInfo.getName(builtinID));
1734
1735 // Predicated intrinsics with _z suffix.
1736 if (typeFlags.getMergeType() == SVETypeFlags::MergeZero) {
1737 cgm.errorNYI(expr->getSourceRange(),
1738 std::string("unimplemented AArch64 builtin call: ") +
1739 getContext().BuiltinInfo.getName(builtinID));
1740 }
1741
1742 llvm::StringRef llvmIntrName = getLLVMIntrNameNoPrefix(
1743 static_cast<llvm::Intrinsic::ID>(builtinIntrInfo->LLVMIntrinsic));
1744 auto retTy = convertType(expr->getType());
1745
1746 auto call = builder.emitIntrinsicCallOp(loc, llvmIntrName, retTy,
1747 mlir::ValueRange{ops});
1748 if (call.getType() == retTy)
1749 return call;
1750
1751 // Predicate results must be converted to svbool_t.
1752 if (isa<mlir::VectorType>(retTy) &&
1753 cast<mlir::VectorType>(retTy).isScalable())
1754 cgm.errorNYI(expr->getSourceRange(),
1755 std::string("unimplemented AArch64 builtin call: ") +
1756 getContext().BuiltinInfo.getName(builtinID));
1757 // TODO Handle struct types, e.g. svint8x2_t (update the converter first).
1758
1759 llvm_unreachable("unsupported element count!");
1760 }
1761
1762 // Handle the remaining built-ins.
1763 // -------------------------------
1764 switch (builtinID) {
1765 default:
1766 return std::nullopt;
1767
1768 case SVE::BI__builtin_sve_svreinterpret_b:
1769 case SVE::BI__builtin_sve_svreinterpret_c:
1770 case SVE::BI__builtin_sve_svpsel_lane_b8:
1771 case SVE::BI__builtin_sve_svpsel_lane_b16:
1772 case SVE::BI__builtin_sve_svpsel_lane_b32:
1773 case SVE::BI__builtin_sve_svpsel_lane_b64:
1774 case SVE::BI__builtin_sve_svpsel_lane_c8:
1775 case SVE::BI__builtin_sve_svpsel_lane_c16:
1776 case SVE::BI__builtin_sve_svpsel_lane_c32:
1777 case SVE::BI__builtin_sve_svpsel_lane_c64:
1778 case SVE::BI__builtin_sve_svmov_b_z:
1779 case SVE::BI__builtin_sve_svnot_b_z:
1780 case SVE::BI__builtin_sve_svmovlb_u16:
1781 case SVE::BI__builtin_sve_svmovlb_u32:
1782 case SVE::BI__builtin_sve_svmovlb_u64:
1783 case SVE::BI__builtin_sve_svmovlb_s16:
1784 case SVE::BI__builtin_sve_svmovlb_s32:
1785 case SVE::BI__builtin_sve_svmovlb_s64:
1786 case SVE::BI__builtin_sve_svmovlt_u16:
1787 case SVE::BI__builtin_sve_svmovlt_u32:
1788 case SVE::BI__builtin_sve_svmovlt_u64:
1789 case SVE::BI__builtin_sve_svmovlt_s16:
1790 case SVE::BI__builtin_sve_svmovlt_s32:
1791 case SVE::BI__builtin_sve_svmovlt_s64:
1792 case SVE::BI__builtin_sve_svpmullt_u16:
1793 case SVE::BI__builtin_sve_svpmullt_u64:
1794 case SVE::BI__builtin_sve_svpmullt_n_u16:
1795 case SVE::BI__builtin_sve_svpmullt_n_u64:
1796 case SVE::BI__builtin_sve_svpmullb_u16:
1797 case SVE::BI__builtin_sve_svpmullb_u64:
1798 case SVE::BI__builtin_sve_svpmullb_n_u16:
1799 case SVE::BI__builtin_sve_svpmullb_n_u64:
1800 cgm.errorNYI(expr->getSourceRange(),
1801 std::string("unimplemented AArch64 builtin call: ") +
1802 getContext().BuiltinInfo.getName(builtinID));
1803 return mlir::Value{};
1804
1805 case SVE::BI__builtin_sve_svdup_n_b8:
1806 case SVE::BI__builtin_sve_svdup_n_b16:
1807 case SVE::BI__builtin_sve_svdup_n_b32:
1808 case SVE::BI__builtin_sve_svdup_n_b64: {
1809 // Cast from cir.bool (input type) to cir.int<u, 1> (element type of the
1810 // result vector).
1811 auto dup = builder.createBitcast(ops[0], builder.getUIntNTy(1));
1812
1813 // Splat
1814 dup = cir::VecSplatOp::create(builder, loc, getSVEType(typeFlags), dup);
1815
1816 // Cast to svbool_t, i.e. <vscale x 16 x i1>. The actual result could be
1817 // e.g. <vscale x 8 x i1> (for b16), but only svbool_t (i.e. full
1818 // predicate register) is "storable" (as per SVE ABI).
1819 return builtinID == SVE::BI__builtin_sve_svdup_n_b8
1820 ? dup
1821 : emitSVEPredicateCast(dup, 16, loc);
1822 }
1823
1824 case SVE::BI__builtin_sve_svdupq_n_b8:
1825 case SVE::BI__builtin_sve_svdupq_n_b16:
1826 case SVE::BI__builtin_sve_svdupq_n_b32:
1827 case SVE::BI__builtin_sve_svdupq_n_b64:
1828 case SVE::BI__builtin_sve_svdupq_n_u8:
1829 case SVE::BI__builtin_sve_svdupq_n_s8:
1830 case SVE::BI__builtin_sve_svdupq_n_u64:
1831 case SVE::BI__builtin_sve_svdupq_n_f64:
1832 case SVE::BI__builtin_sve_svdupq_n_s64:
1833 case SVE::BI__builtin_sve_svdupq_n_u16:
1834 case SVE::BI__builtin_sve_svdupq_n_f16:
1835 case SVE::BI__builtin_sve_svdupq_n_bf16:
1836 case SVE::BI__builtin_sve_svdupq_n_s16:
1837 case SVE::BI__builtin_sve_svdupq_n_u32:
1838 case SVE::BI__builtin_sve_svdupq_n_f32:
1839 case SVE::BI__builtin_sve_svdupq_n_s32:
1840 cgm.errorNYI(expr->getSourceRange(),
1841 std::string("unimplemented AArch64 builtin call: ") +
1842 getContext().BuiltinInfo.getName(builtinID));
1843 return mlir::Value{};
1844
1845 case SVE::BI__builtin_sve_svpfalse_b:
1846 return builder.getNullValue(convertType(expr->getType()),
1847 getLoc(expr->getExprLoc()));
1848
1849 case SVE::BI__builtin_sve_svpfalse_c:
1850 cgm.errorNYI(expr->getSourceRange(),
1851 std::string("unimplemented AArch64 builtin call: ") +
1852 getContext().BuiltinInfo.getName(builtinID));
1853 return mlir::Value{};
1854
1855 case SVE::BI__builtin_sve_svlen_u8:
1856 case SVE::BI__builtin_sve_svlen_s8:
1857 return genVscaleTimesFactor(loc, builder, convertType(expr->getType()), 16);
1858
1859 case SVE::BI__builtin_sve_svlen_u16:
1860 case SVE::BI__builtin_sve_svlen_s16:
1861 case SVE::BI__builtin_sve_svlen_f16:
1862 case SVE::BI__builtin_sve_svlen_bf16:
1863 return genVscaleTimesFactor(loc, builder, convertType(expr->getType()), 8);
1864
1865 case SVE::BI__builtin_sve_svlen_u32:
1866 case SVE::BI__builtin_sve_svlen_s32:
1867 case SVE::BI__builtin_sve_svlen_f32:
1868 return genVscaleTimesFactor(loc, builder, convertType(expr->getType()), 4);
1869
1870 case SVE::BI__builtin_sve_svlen_u64:
1871 case SVE::BI__builtin_sve_svlen_s64:
1872 case SVE::BI__builtin_sve_svlen_f64:
1873 return genVscaleTimesFactor(loc, builder, convertType(expr->getType()), 2);
1874
1875 case SVE::BI__builtin_sve_svtbl2_u8:
1876 case SVE::BI__builtin_sve_svtbl2_s8:
1877 case SVE::BI__builtin_sve_svtbl2_u16:
1878 case SVE::BI__builtin_sve_svtbl2_s16:
1879 case SVE::BI__builtin_sve_svtbl2_u32:
1880 case SVE::BI__builtin_sve_svtbl2_s32:
1881 case SVE::BI__builtin_sve_svtbl2_u64:
1882 case SVE::BI__builtin_sve_svtbl2_s64:
1883 case SVE::BI__builtin_sve_svtbl2_f16:
1884 case SVE::BI__builtin_sve_svtbl2_bf16:
1885 case SVE::BI__builtin_sve_svtbl2_f32:
1886 case SVE::BI__builtin_sve_svtbl2_f64:
1887 case SVE::BI__builtin_sve_svset_neonq_s8:
1888 case SVE::BI__builtin_sve_svset_neonq_s16:
1889 case SVE::BI__builtin_sve_svset_neonq_s32:
1890 case SVE::BI__builtin_sve_svset_neonq_s64:
1891 case SVE::BI__builtin_sve_svset_neonq_u8:
1892 case SVE::BI__builtin_sve_svset_neonq_u16:
1893 case SVE::BI__builtin_sve_svset_neonq_u32:
1894 case SVE::BI__builtin_sve_svset_neonq_u64:
1895 case SVE::BI__builtin_sve_svset_neonq_f16:
1896 case SVE::BI__builtin_sve_svset_neonq_f32:
1897 case SVE::BI__builtin_sve_svset_neonq_f64:
1898 case SVE::BI__builtin_sve_svset_neonq_bf16:
1899 case SVE::BI__builtin_sve_svset_neonq_mf8:
1900 case SVE::BI__builtin_sve_svget_neonq_s8:
1901 case SVE::BI__builtin_sve_svget_neonq_s16:
1902 case SVE::BI__builtin_sve_svget_neonq_s32:
1903 case SVE::BI__builtin_sve_svget_neonq_s64:
1904 case SVE::BI__builtin_sve_svget_neonq_u8:
1905 case SVE::BI__builtin_sve_svget_neonq_u16:
1906 case SVE::BI__builtin_sve_svget_neonq_u32:
1907 case SVE::BI__builtin_sve_svget_neonq_u64:
1908 case SVE::BI__builtin_sve_svget_neonq_f16:
1909 case SVE::BI__builtin_sve_svget_neonq_f32:
1910 case SVE::BI__builtin_sve_svget_neonq_f64:
1911 case SVE::BI__builtin_sve_svget_neonq_bf16:
1912 case SVE::BI__builtin_sve_svget_neonq_mf8:
1913 case SVE::BI__builtin_sve_svdup_neonq_s8:
1914 case SVE::BI__builtin_sve_svdup_neonq_s16:
1915 case SVE::BI__builtin_sve_svdup_neonq_s32:
1916 case SVE::BI__builtin_sve_svdup_neonq_s64:
1917 case SVE::BI__builtin_sve_svdup_neonq_u8:
1918 case SVE::BI__builtin_sve_svdup_neonq_u16:
1919 case SVE::BI__builtin_sve_svdup_neonq_u32:
1920 case SVE::BI__builtin_sve_svdup_neonq_u64:
1921 case SVE::BI__builtin_sve_svdup_neonq_f16:
1922 case SVE::BI__builtin_sve_svdup_neonq_f32:
1923 case SVE::BI__builtin_sve_svdup_neonq_f64:
1924 case SVE::BI__builtin_sve_svdup_neonq_bf16:
1925 case SVE::BI__builtin_sve_svdup_neonq_mf8:
1926 cgm.errorNYI(expr->getSourceRange(),
1927 std::string("unimplemented AArch64 builtin call: ") +
1928 getContext().BuiltinInfo.getName(builtinID));
1929 return mlir::Value{};
1930 }
1931
1932 // Unreachable: All cases in the switch above return.
1933}
1934
1935std::optional<mlir::Value>
1937 const CallExpr *expr) {
1939
1940 cgm.errorNYI(expr->getSourceRange(),
1941 std::string("unimplemented AArch64 builtin call: ") +
1942 getContext().BuiltinInfo.getName(builtinID));
1943 return mlir::Value{};
1944}
1945
1946// Some intrinsics are equivalent for codegen.
1947static const std::pair<unsigned, unsigned> neonEquivalentIntrinsicMap[] = {
1948 {
1949 NEON::BI__builtin_neon_vabd_f16,
1950 NEON::BI__builtin_neon_vabd_v,
1951 },
1952 {
1953 NEON::BI__builtin_neon_vabdq_f16,
1954 NEON::BI__builtin_neon_vabdq_v,
1955 },
1956 {
1957 NEON::BI__builtin_neon_vabs_f16,
1958 NEON::BI__builtin_neon_vabs_v,
1959 },
1960 {
1961 NEON::BI__builtin_neon_vabsq_f16,
1962 NEON::BI__builtin_neon_vabsq_v,
1963 },
1964 {
1965 NEON::BI__builtin_neon_vcage_f16,
1966 NEON::BI__builtin_neon_vcage_v,
1967 },
1968 {
1969 NEON::BI__builtin_neon_vcageq_f16,
1970 NEON::BI__builtin_neon_vcageq_v,
1971 },
1972 {
1973 NEON::BI__builtin_neon_vcagt_f16,
1974 NEON::BI__builtin_neon_vcagt_v,
1975 },
1976 {
1977 NEON::BI__builtin_neon_vcagtq_f16,
1978 NEON::BI__builtin_neon_vcagtq_v,
1979 },
1980 {
1981 NEON::BI__builtin_neon_vcale_f16,
1982 NEON::BI__builtin_neon_vcale_v,
1983 },
1984 {
1985 NEON::BI__builtin_neon_vcaleq_f16,
1986 NEON::BI__builtin_neon_vcaleq_v,
1987 },
1988 {
1989 NEON::BI__builtin_neon_vcalt_f16,
1990 NEON::BI__builtin_neon_vcalt_v,
1991 },
1992 {
1993 NEON::BI__builtin_neon_vcaltq_f16,
1994 NEON::BI__builtin_neon_vcaltq_v,
1995 },
1996 {
1997 NEON::BI__builtin_neon_vceqz_f16,
1998 NEON::BI__builtin_neon_vceqz_v,
1999 },
2000 {
2001 NEON::BI__builtin_neon_vceqzq_f16,
2002 NEON::BI__builtin_neon_vceqzq_v,
2003 },
2004 {
2005 NEON::BI__builtin_neon_vcgez_f16,
2006 NEON::BI__builtin_neon_vcgez_v,
2007 },
2008 {
2009 NEON::BI__builtin_neon_vcgezq_f16,
2010 NEON::BI__builtin_neon_vcgezq_v,
2011 },
2012 {
2013 NEON::BI__builtin_neon_vcgtz_f16,
2014 NEON::BI__builtin_neon_vcgtz_v,
2015 },
2016 {
2017 NEON::BI__builtin_neon_vcgtzq_f16,
2018 NEON::BI__builtin_neon_vcgtzq_v,
2019 },
2020 {
2021 NEON::BI__builtin_neon_vclez_f16,
2022 NEON::BI__builtin_neon_vclez_v,
2023 },
2024 {
2025 NEON::BI__builtin_neon_vclezq_f16,
2026 NEON::BI__builtin_neon_vclezq_v,
2027 },
2028 {
2029 NEON::BI__builtin_neon_vcltz_f16,
2030 NEON::BI__builtin_neon_vcltz_v,
2031 },
2032 {
2033 NEON::BI__builtin_neon_vcltzq_f16,
2034 NEON::BI__builtin_neon_vcltzq_v,
2035 },
2036 {
2037 NEON::BI__builtin_neon_vfma_f16,
2038 NEON::BI__builtin_neon_vfma_v,
2039 },
2040 {
2041 NEON::BI__builtin_neon_vfma_lane_f16,
2042 NEON::BI__builtin_neon_vfma_lane_v,
2043 },
2044 {
2045 NEON::BI__builtin_neon_vfma_laneq_f16,
2046 NEON::BI__builtin_neon_vfma_laneq_v,
2047 },
2048 {
2049 NEON::BI__builtin_neon_vfmaq_f16,
2050 NEON::BI__builtin_neon_vfmaq_v,
2051 },
2052 {
2053 NEON::BI__builtin_neon_vfmaq_lane_f16,
2054 NEON::BI__builtin_neon_vfmaq_lane_v,
2055 },
2056 {
2057 NEON::BI__builtin_neon_vfmaq_laneq_f16,
2058 NEON::BI__builtin_neon_vfmaq_laneq_v,
2059 },
2060 {
2061 NEON::BI__builtin_neon_vmax_f16,
2062 NEON::BI__builtin_neon_vmax_v,
2063 },
2064 {
2065 NEON::BI__builtin_neon_vmaxnm_f16,
2066 NEON::BI__builtin_neon_vmaxnm_v,
2067 },
2068 {
2069 NEON::BI__builtin_neon_vmaxnmq_f16,
2070 NEON::BI__builtin_neon_vmaxnmq_v,
2071 },
2072 {
2073 NEON::BI__builtin_neon_vmaxq_f16,
2074 NEON::BI__builtin_neon_vmaxq_v,
2075 },
2076 {
2077 NEON::BI__builtin_neon_vmin_f16,
2078 NEON::BI__builtin_neon_vmin_v,
2079 },
2080 {
2081 NEON::BI__builtin_neon_vminnm_f16,
2082 NEON::BI__builtin_neon_vminnm_v,
2083 },
2084 {
2085 NEON::BI__builtin_neon_vminnmq_f16,
2086 NEON::BI__builtin_neon_vminnmq_v,
2087 },
2088 {
2089 NEON::BI__builtin_neon_vminq_f16,
2090 NEON::BI__builtin_neon_vminq_v,
2091 },
2092 {
2093 NEON::BI__builtin_neon_vmulx_f16,
2094 NEON::BI__builtin_neon_vmulx_v,
2095 },
2096 {
2097 NEON::BI__builtin_neon_vmulxq_f16,
2098 NEON::BI__builtin_neon_vmulxq_v,
2099 },
2100 {
2101 NEON::BI__builtin_neon_vpadd_f16,
2102 NEON::BI__builtin_neon_vpadd_v,
2103 },
2104 {
2105 NEON::BI__builtin_neon_vpaddq_f16,
2106 NEON::BI__builtin_neon_vpaddq_v,
2107 },
2108 {
2109 NEON::BI__builtin_neon_vpmax_f16,
2110 NEON::BI__builtin_neon_vpmax_v,
2111 },
2112 {
2113 NEON::BI__builtin_neon_vpmaxnm_f16,
2114 NEON::BI__builtin_neon_vpmaxnm_v,
2115 },
2116 {
2117 NEON::BI__builtin_neon_vpmaxnmq_f16,
2118 NEON::BI__builtin_neon_vpmaxnmq_v,
2119 },
2120 {
2121 NEON::BI__builtin_neon_vpmaxq_f16,
2122 NEON::BI__builtin_neon_vpmaxq_v,
2123 },
2124 {
2125 NEON::BI__builtin_neon_vpmin_f16,
2126 NEON::BI__builtin_neon_vpmin_v,
2127 },
2128 {
2129 NEON::BI__builtin_neon_vpminnm_f16,
2130 NEON::BI__builtin_neon_vpminnm_v,
2131 },
2132 {
2133 NEON::BI__builtin_neon_vpminnmq_f16,
2134 NEON::BI__builtin_neon_vpminnmq_v,
2135 },
2136 {
2137 NEON::BI__builtin_neon_vpminq_f16,
2138 NEON::BI__builtin_neon_vpminq_v,
2139 },
2140 {
2141 NEON::BI__builtin_neon_vrecpe_f16,
2142 NEON::BI__builtin_neon_vrecpe_v,
2143 },
2144 {
2145 NEON::BI__builtin_neon_vrecpeq_f16,
2146 NEON::BI__builtin_neon_vrecpeq_v,
2147 },
2148 {
2149 NEON::BI__builtin_neon_vrecps_f16,
2150 NEON::BI__builtin_neon_vrecps_v,
2151 },
2152 {
2153 NEON::BI__builtin_neon_vrecpsq_f16,
2154 NEON::BI__builtin_neon_vrecpsq_v,
2155 },
2156 {
2157 NEON::BI__builtin_neon_vrnd_f16,
2158 NEON::BI__builtin_neon_vrnd_v,
2159 },
2160 {
2161 NEON::BI__builtin_neon_vrnda_f16,
2162 NEON::BI__builtin_neon_vrnda_v,
2163 },
2164 {
2165 NEON::BI__builtin_neon_vrndaq_f16,
2166 NEON::BI__builtin_neon_vrndaq_v,
2167 },
2168 {
2169 NEON::BI__builtin_neon_vrndi_f16,
2170 NEON::BI__builtin_neon_vrndi_v,
2171 },
2172 {
2173 NEON::BI__builtin_neon_vrndiq_f16,
2174 NEON::BI__builtin_neon_vrndiq_v,
2175 },
2176 {
2177 NEON::BI__builtin_neon_vrndm_f16,
2178 NEON::BI__builtin_neon_vrndm_v,
2179 },
2180 {
2181 NEON::BI__builtin_neon_vrndmq_f16,
2182 NEON::BI__builtin_neon_vrndmq_v,
2183 },
2184 {
2185 NEON::BI__builtin_neon_vrndn_f16,
2186 NEON::BI__builtin_neon_vrndn_v,
2187 },
2188 {
2189 NEON::BI__builtin_neon_vrndnq_f16,
2190 NEON::BI__builtin_neon_vrndnq_v,
2191 },
2192 {
2193 NEON::BI__builtin_neon_vrndp_f16,
2194 NEON::BI__builtin_neon_vrndp_v,
2195 },
2196 {
2197 NEON::BI__builtin_neon_vrndpq_f16,
2198 NEON::BI__builtin_neon_vrndpq_v,
2199 },
2200 {
2201 NEON::BI__builtin_neon_vrndq_f16,
2202 NEON::BI__builtin_neon_vrndq_v,
2203 },
2204 {
2205 NEON::BI__builtin_neon_vrndx_f16,
2206 NEON::BI__builtin_neon_vrndx_v,
2207 },
2208 {
2209 NEON::BI__builtin_neon_vrndxq_f16,
2210 NEON::BI__builtin_neon_vrndxq_v,
2211 },
2212 {
2213 NEON::BI__builtin_neon_vrsqrte_f16,
2214 NEON::BI__builtin_neon_vrsqrte_v,
2215 },
2216 {
2217 NEON::BI__builtin_neon_vrsqrteq_f16,
2218 NEON::BI__builtin_neon_vrsqrteq_v,
2219 },
2220 {
2221 NEON::BI__builtin_neon_vrsqrts_f16,
2222 NEON::BI__builtin_neon_vrsqrts_v,
2223 },
2224 {
2225 NEON::BI__builtin_neon_vrsqrtsq_f16,
2226 NEON::BI__builtin_neon_vrsqrtsq_v,
2227 },
2228 {
2229 NEON::BI__builtin_neon_vsqrt_f16,
2230 NEON::BI__builtin_neon_vsqrt_v,
2231 },
2232 {
2233 NEON::BI__builtin_neon_vsqrtq_f16,
2234 NEON::BI__builtin_neon_vsqrtq_v,
2235 },
2236 // The mangling rules cause us to have one ID for each type for
2237 // vldap1(q)_lane and vstl1(q)_lane, but codegen is equivalent for all of
2238 // them. Choose an arbitrary one to be handled as tha canonical variation.
2239 {NEON::BI__builtin_neon_vldap1_lane_u64,
2240 NEON::BI__builtin_neon_vldap1_lane_s64},
2241 {NEON::BI__builtin_neon_vldap1_lane_f64,
2242 NEON::BI__builtin_neon_vldap1_lane_s64},
2243 {NEON::BI__builtin_neon_vldap1_lane_p64,
2244 NEON::BI__builtin_neon_vldap1_lane_s64},
2245 {NEON::BI__builtin_neon_vldap1q_lane_u64,
2246 NEON::BI__builtin_neon_vldap1q_lane_s64},
2247 {NEON::BI__builtin_neon_vldap1q_lane_f64,
2248 NEON::BI__builtin_neon_vldap1q_lane_s64},
2249 {NEON::BI__builtin_neon_vldap1q_lane_p64,
2250 NEON::BI__builtin_neon_vldap1q_lane_s64},
2251 {NEON::BI__builtin_neon_vstl1_lane_u64,
2252 NEON::BI__builtin_neon_vstl1_lane_s64},
2253 {NEON::BI__builtin_neon_vstl1_lane_f64,
2254 NEON::BI__builtin_neon_vstl1_lane_s64},
2255 {NEON::BI__builtin_neon_vstl1_lane_p64,
2256 NEON::BI__builtin_neon_vstl1_lane_s64},
2257 {NEON::BI__builtin_neon_vstl1q_lane_u64,
2258 NEON::BI__builtin_neon_vstl1q_lane_s64},
2259 {NEON::BI__builtin_neon_vstl1q_lane_f64,
2260 NEON::BI__builtin_neon_vstl1q_lane_s64},
2261 {NEON::BI__builtin_neon_vstl1q_lane_p64,
2262 NEON::BI__builtin_neon_vstl1q_lane_s64},
2263};
2264
2265std::optional<mlir::Value>
2268 llvm::Triple::ArchType arch) {
2269 if (builtinID >= clang::AArch64::FirstSVEBuiltin &&
2270 builtinID <= clang::AArch64::LastSVEBuiltin)
2271 return emitAArch64SVEBuiltinExpr(builtinID, expr);
2272
2273 if (builtinID >= clang::AArch64::FirstSMEBuiltin &&
2274 builtinID <= clang::AArch64::LastSMEBuiltin)
2275 return emitAArch64SMEBuiltinExpr(builtinID, expr);
2276
2277 if (builtinID == Builtin::BI__builtin_cpu_supports) {
2278 cgm.errorNYI(expr->getSourceRange(),
2279 std::string("unimplemented AArch64 builtin call: ") +
2280 getContext().BuiltinInfo.getName(builtinID));
2281 return mlir::Value{};
2282 }
2283
2284 switch (builtinID) {
2285 default:
2286 break;
2287 case clang::AArch64::BI__builtin_arm_nop:
2288 case clang::AArch64::BI__builtin_arm_yield:
2289 case clang::AArch64::BI__yield:
2290 case clang::AArch64::BI__builtin_arm_wfe:
2291 case clang::AArch64::BI__wfe:
2292 case clang::AArch64::BI__builtin_arm_wfi:
2293 case clang::AArch64::BI__wfi:
2294 case clang::AArch64::BI__builtin_arm_sev:
2295 case clang::AArch64::BI__sev:
2296 case clang::AArch64::BI__builtin_arm_sevl:
2297 case clang::AArch64::BI__sevl:
2298 cgm.errorNYI(expr->getSourceRange(),
2299 std::string("unimplemented AArch64 builtin call: ") +
2300 getContext().BuiltinInfo.getName(builtinID));
2301 return mlir::Value{};
2302 }
2303
2304 if (builtinID == clang::AArch64::BI__builtin_arm_trap) {
2305 cgm.errorNYI(expr->getSourceRange(),
2306 std::string("unimplemented AArch64 builtin call: ") +
2307 getContext().BuiltinInfo.getName(builtinID));
2308 return mlir::Value{};
2309 }
2310
2311 if (builtinID == clang::AArch64::BI__builtin_arm_get_sme_state) {
2312 cgm.errorNYI(expr->getSourceRange(),
2313 std::string("unimplemented AArch64 builtin call: ") +
2314 getContext().BuiltinInfo.getName(builtinID));
2315 return mlir::Value{};
2316 }
2317
2318 if (builtinID == clang::AArch64::BI__builtin_arm_rbit) {
2319 cgm.errorNYI(expr->getSourceRange(),
2320 std::string("unimplemented AArch64 builtin call: ") +
2321 getContext().BuiltinInfo.getName(builtinID));
2322 return mlir::Value{};
2323 }
2324 if (builtinID == clang::AArch64::BI__builtin_arm_rbit64) {
2325 cgm.errorNYI(expr->getSourceRange(),
2326 std::string("unimplemented AArch64 builtin call: ") +
2327 getContext().BuiltinInfo.getName(builtinID));
2328 return mlir::Value{};
2329 }
2330
2331 if (builtinID == clang::AArch64::BI__builtin_arm_clz ||
2332 builtinID == clang::AArch64::BI__builtin_arm_clz64) {
2333 cgm.errorNYI(expr->getSourceRange(),
2334 std::string("unimplemented AArch64 builtin call: ") +
2335 getContext().BuiltinInfo.getName(builtinID));
2336 return mlir::Value{};
2337 }
2338
2339 if (builtinID == clang::AArch64::BI__builtin_arm_cls) {
2340 cgm.errorNYI(expr->getSourceRange(),
2341 std::string("unimplemented AArch64 builtin call: ") +
2342 getContext().BuiltinInfo.getName(builtinID));
2343 return mlir::Value{};
2344 }
2345 if (builtinID == clang::AArch64::BI__builtin_arm_cls64) {
2346 cgm.errorNYI(expr->getSourceRange(),
2347 std::string("unimplemented AArch64 builtin call: ") +
2348 getContext().BuiltinInfo.getName(builtinID));
2349 return mlir::Value{};
2350 }
2351
2352 if (builtinID == clang::AArch64::BI__builtin_arm_rint32zf ||
2353 builtinID == clang::AArch64::BI__builtin_arm_rint32z) {
2354 cgm.errorNYI(expr->getSourceRange(),
2355 std::string("unimplemented AArch64 builtin call: ") +
2356 getContext().BuiltinInfo.getName(builtinID));
2357 return mlir::Value{};
2358 }
2359
2360 if (builtinID == clang::AArch64::BI__builtin_arm_rint64zf ||
2361 builtinID == clang::AArch64::BI__builtin_arm_rint64z) {
2362 cgm.errorNYI(expr->getSourceRange(),
2363 std::string("unimplemented AArch64 builtin call: ") +
2364 getContext().BuiltinInfo.getName(builtinID));
2365 return mlir::Value{};
2366 }
2367
2368 if (builtinID == clang::AArch64::BI__builtin_arm_rint32xf ||
2369 builtinID == clang::AArch64::BI__builtin_arm_rint32x) {
2370 cgm.errorNYI(expr->getSourceRange(),
2371 std::string("unimplemented AArch64 builtin call: ") +
2372 getContext().BuiltinInfo.getName(builtinID));
2373 return mlir::Value{};
2374 }
2375
2376 if (builtinID == clang::AArch64::BI__builtin_arm_rint64xf ||
2377 builtinID == clang::AArch64::BI__builtin_arm_rint64x) {
2378 cgm.errorNYI(expr->getSourceRange(),
2379 std::string("unimplemented AArch64 builtin call: ") +
2380 getContext().BuiltinInfo.getName(builtinID));
2381 return mlir::Value{};
2382 }
2383
2384 if (builtinID == clang::AArch64::BI__builtin_arm_jcvt) {
2385 cgm.errorNYI(expr->getSourceRange(),
2386 std::string("unimplemented AArch64 builtin call: ") +
2387 getContext().BuiltinInfo.getName(builtinID));
2388 return mlir::Value{};
2389 }
2390
2391 if (builtinID == clang::AArch64::BI__builtin_arm_ld64b ||
2392 builtinID == clang::AArch64::BI__builtin_arm_st64b ||
2393 builtinID == clang::AArch64::BI__builtin_arm_st64bv ||
2394 builtinID == clang::AArch64::BI__builtin_arm_st64bv0) {
2395 cgm.errorNYI(expr->getSourceRange(),
2396 std::string("unimplemented AArch64 builtin call: ") +
2397 getContext().BuiltinInfo.getName(builtinID));
2398 return mlir::Value{};
2399 }
2400
2401 if (builtinID == clang::AArch64::BI__builtin_arm_rndr ||
2402 builtinID == clang::AArch64::BI__builtin_arm_rndrrs) {
2403 cgm.errorNYI(expr->getSourceRange(),
2404 std::string("unimplemented AArch64 builtin call: ") +
2405 getContext().BuiltinInfo.getName(builtinID));
2406 return mlir::Value{};
2407 }
2408
2409 if (builtinID == clang::AArch64::BI__clear_cache) {
2410 cgm.errorNYI(expr->getSourceRange(),
2411 std::string("unimplemented AArch64 builtin call: ") +
2412 getContext().BuiltinInfo.getName(builtinID));
2413 return mlir::Value{};
2414 }
2415
2416 if ((builtinID == clang::AArch64::BI__builtin_arm_ldrex ||
2417 builtinID == clang::AArch64::BI__builtin_arm_ldaex) &&
2418 getContext().getTypeSize(expr->getType()) == 128) {
2419 cgm.errorNYI(expr->getSourceRange(),
2420 std::string("unimplemented AArch64 builtin call: ") +
2421 getContext().BuiltinInfo.getName(builtinID));
2422 return mlir::Value{};
2423 }
2424 if (builtinID == clang::AArch64::BI__builtin_arm_ldrex ||
2425 builtinID == clang::AArch64::BI__builtin_arm_ldaex) {
2426 cgm.errorNYI(expr->getSourceRange(),
2427 std::string("unimplemented AArch64 builtin call: ") +
2428 getContext().BuiltinInfo.getName(builtinID));
2429 return mlir::Value{};
2430 }
2431
2432 if ((builtinID == clang::AArch64::BI__builtin_arm_strex ||
2433 builtinID == clang::AArch64::BI__builtin_arm_stlex) &&
2434 getContext().getTypeSize(expr->getArg(0)->getType()) == 128) {
2435 cgm.errorNYI(expr->getSourceRange(),
2436 std::string("unimplemented AArch64 builtin call: ") +
2437 getContext().BuiltinInfo.getName(builtinID));
2438 return mlir::Value{};
2439 }
2440
2441 if (builtinID == clang::AArch64::BI__builtin_arm_strex ||
2442 builtinID == clang::AArch64::BI__builtin_arm_stlex) {
2443 cgm.errorNYI(expr->getSourceRange(),
2444 std::string("unimplemented AArch64 builtin call: ") +
2445 getContext().BuiltinInfo.getName(builtinID));
2446 return mlir::Value{};
2447 }
2448
2449 if (builtinID == clang::AArch64::BI__getReg ||
2450 builtinID == clang::AArch64::BI__setReg ||
2451 builtinID == clang::AArch64::BI__getRegFp ||
2452 builtinID == clang::AArch64::BI__setRegFp) {
2453 cgm.errorNYI(expr->getSourceRange(),
2454 std::string("unimplemented AArch64 builtin call: ") +
2455 getContext().BuiltinInfo.getName(builtinID));
2456 return mlir::Value{};
2457 }
2458
2459 if (builtinID == clang::AArch64::BI__break) {
2460 cgm.errorNYI(expr->getSourceRange(),
2461 std::string("unimplemented AArch64 builtin call: ") +
2462 getContext().BuiltinInfo.getName(builtinID));
2463 return mlir::Value{};
2464 }
2465
2466 if (builtinID == clang::AArch64::BI__builtin_arm_clrex) {
2467 cgm.errorNYI(expr->getSourceRange(),
2468 std::string("unimplemented AArch64 builtin call: ") +
2469 getContext().BuiltinInfo.getName(builtinID));
2470 return mlir::Value{};
2471 }
2472
2473 if (builtinID == clang::AArch64::BI_ReadWriteBarrier) {
2474 cgm.errorNYI(expr->getSourceRange(),
2475 std::string("unimplemented AArch64 builtin call: ") +
2476 getContext().BuiltinInfo.getName(builtinID));
2477 return mlir::Value{};
2478 }
2479
2480 // CRC32
2481 Intrinsic::ID crcIntrinsicID = Intrinsic::not_intrinsic;
2482 switch (builtinID) {
2483 case clang::AArch64::BI__builtin_arm_crc32b:
2484 crcIntrinsicID = Intrinsic::aarch64_crc32b;
2485 break;
2486 case clang::AArch64::BI__builtin_arm_crc32cb:
2487 crcIntrinsicID = Intrinsic::aarch64_crc32cb;
2488 break;
2489 case clang::AArch64::BI__builtin_arm_crc32h:
2490 crcIntrinsicID = Intrinsic::aarch64_crc32h;
2491 break;
2492 case clang::AArch64::BI__builtin_arm_crc32ch:
2493 crcIntrinsicID = Intrinsic::aarch64_crc32ch;
2494 break;
2495 case clang::AArch64::BI__builtin_arm_crc32w:
2496 crcIntrinsicID = Intrinsic::aarch64_crc32w;
2497 break;
2498 case clang::AArch64::BI__builtin_arm_crc32cw:
2499 crcIntrinsicID = Intrinsic::aarch64_crc32cw;
2500 break;
2501 case clang::AArch64::BI__builtin_arm_crc32d:
2502 crcIntrinsicID = Intrinsic::aarch64_crc32x;
2503 break;
2504 case clang::AArch64::BI__builtin_arm_crc32cd:
2505 crcIntrinsicID = Intrinsic::aarch64_crc32cx;
2506 break;
2507 }
2508
2509 if (crcIntrinsicID != Intrinsic::not_intrinsic) {
2510 cgm.errorNYI(expr->getSourceRange(),
2511 std::string("unimplemented AArch64 builtin call: ") +
2512 getContext().BuiltinInfo.getName(builtinID));
2513 return mlir::Value{};
2514 }
2515
2516 // Memory Operations (MOPS)
2517 if (builtinID == AArch64::BI__builtin_arm_mops_memset_tag) {
2518 cgm.errorNYI(expr->getSourceRange(),
2519 std::string("unimplemented AArch64 builtin call: ") +
2520 getContext().BuiltinInfo.getName(builtinID));
2521 return mlir::Value{};
2522 }
2523
2524 // Memory Tagging Extensions (MTE) Intrinsics
2525 Intrinsic::ID mteIntrinsicID = Intrinsic::not_intrinsic;
2526 switch (builtinID) {
2527 case clang::AArch64::BI__builtin_arm_irg:
2528 mteIntrinsicID = Intrinsic::aarch64_irg;
2529 break;
2530 case clang::AArch64::BI__builtin_arm_addg:
2531 mteIntrinsicID = Intrinsic::aarch64_addg;
2532 break;
2533 case clang::AArch64::BI__builtin_arm_gmi:
2534 mteIntrinsicID = Intrinsic::aarch64_gmi;
2535 break;
2536 case clang::AArch64::BI__builtin_arm_ldg:
2537 mteIntrinsicID = Intrinsic::aarch64_ldg;
2538 break;
2539 case clang::AArch64::BI__builtin_arm_stg:
2540 mteIntrinsicID = Intrinsic::aarch64_stg;
2541 break;
2542 case clang::AArch64::BI__builtin_arm_subp:
2543 mteIntrinsicID = Intrinsic::aarch64_subp;
2544 break;
2545 }
2546
2547 if (mteIntrinsicID != Intrinsic::not_intrinsic) {
2548 cgm.errorNYI(expr->getSourceRange(),
2549 std::string("unimplemented AArch64 builtin call: ") +
2550 getContext().BuiltinInfo.getName(builtinID));
2551 return mlir::Value{};
2552 }
2553
2554 if (builtinID == clang::AArch64::BI__builtin_arm_rsr ||
2555 builtinID == clang::AArch64::BI__builtin_arm_rsr64 ||
2556 builtinID == clang::AArch64::BI__builtin_arm_rsr128 ||
2557 builtinID == clang::AArch64::BI__builtin_arm_rsrp ||
2558 builtinID == clang::AArch64::BI__builtin_arm_wsr ||
2559 builtinID == clang::AArch64::BI__builtin_arm_wsr64 ||
2560 builtinID == clang::AArch64::BI__builtin_arm_wsr128 ||
2561 builtinID == clang::AArch64::BI__builtin_arm_wsrp) {
2562 cgm.errorNYI(expr->getSourceRange(),
2563 std::string("unimplemented AArch64 builtin call: ") +
2564 getContext().BuiltinInfo.getName(builtinID));
2565 return mlir::Value{};
2566 }
2567
2568 if (builtinID == clang::AArch64::BI_ReadStatusReg ||
2569 builtinID == clang::AArch64::BI_WriteStatusReg ||
2570 builtinID == clang::AArch64::BI__sys) {
2571 cgm.errorNYI(expr->getSourceRange(),
2572 std::string("unimplemented AArch64 builtin call: ") +
2573 getContext().BuiltinInfo.getName(builtinID));
2574 return mlir::Value{};
2575 }
2576
2577 if (builtinID == clang::AArch64::BI_AddressOfReturnAddress) {
2578 cgm.errorNYI(expr->getSourceRange(),
2579 std::string("unimplemented AArch64 builtin call: ") +
2580 getContext().BuiltinInfo.getName(builtinID));
2581 return mlir::Value{};
2582 }
2583
2584 if (builtinID == clang::AArch64::BI__builtin_sponentry) {
2585 cgm.errorNYI(expr->getSourceRange(),
2586 std::string("unimplemented AArch64 builtin call: ") +
2587 getContext().BuiltinInfo.getName(builtinID));
2588 return mlir::Value{};
2589 }
2590
2591 if (builtinID == clang::AArch64::BI__mulh ||
2592 builtinID == clang::AArch64::BI__umulh) {
2593 cgm.errorNYI(expr->getSourceRange(),
2594 std::string("unimplemented AArch64 builtin call: ") +
2595 getContext().BuiltinInfo.getName(builtinID));
2596 return mlir::Value{};
2597 }
2598
2599 if (builtinID == AArch64::BI__writex18byte ||
2600 builtinID == AArch64::BI__writex18word ||
2601 builtinID == AArch64::BI__writex18dword ||
2602 builtinID == AArch64::BI__writex18qword) {
2603 cgm.errorNYI(expr->getSourceRange(),
2604 std::string("unimplemented AArch64 builtin call: ") +
2605 getContext().BuiltinInfo.getName(builtinID));
2606 return mlir::Value{};
2607 }
2608
2609 if (builtinID == AArch64::BI__readx18byte ||
2610 builtinID == AArch64::BI__readx18word ||
2611 builtinID == AArch64::BI__readx18dword ||
2612 builtinID == AArch64::BI__readx18qword) {
2613 cgm.errorNYI(expr->getSourceRange(),
2614 std::string("unimplemented AArch64 builtin call: ") +
2615 getContext().BuiltinInfo.getName(builtinID));
2616 return mlir::Value{};
2617 }
2618
2619 if (builtinID == AArch64::BI__addx18byte ||
2620 builtinID == AArch64::BI__addx18word ||
2621 builtinID == AArch64::BI__addx18dword ||
2622 builtinID == AArch64::BI__addx18qword ||
2623 builtinID == AArch64::BI__incx18byte ||
2624 builtinID == AArch64::BI__incx18word ||
2625 builtinID == AArch64::BI__incx18dword ||
2626 builtinID == AArch64::BI__incx18qword) {
2627 cgm.errorNYI(expr->getSourceRange(),
2628 std::string("unimplemented AArch64 builtin call: ") +
2629 getContext().BuiltinInfo.getName(builtinID));
2630 return mlir::Value{};
2631 }
2632
2633 if (builtinID == AArch64::BI_CopyDoubleFromInt64 ||
2634 builtinID == AArch64::BI_CopyFloatFromInt32 ||
2635 builtinID == AArch64::BI_CopyInt32FromFloat ||
2636 builtinID == AArch64::BI_CopyInt64FromDouble) {
2637 cgm.errorNYI(expr->getSourceRange(),
2638 std::string("unimplemented AArch64 builtin call: ") +
2639 getContext().BuiltinInfo.getName(builtinID));
2640 return mlir::Value{};
2641 }
2642
2643 if (builtinID == AArch64::BI_CountLeadingOnes ||
2644 builtinID == AArch64::BI_CountLeadingOnes64 ||
2645 builtinID == AArch64::BI_CountLeadingZeros ||
2646 builtinID == AArch64::BI_CountLeadingZeros64) {
2647 cgm.errorNYI(expr->getSourceRange(),
2648 std::string("unimplemented AArch64 builtin call: ") +
2649 getContext().BuiltinInfo.getName(builtinID));
2650 return mlir::Value{};
2651 }
2652
2653 if (builtinID == AArch64::BI_CountLeadingSigns ||
2654 builtinID == AArch64::BI_CountLeadingSigns64) {
2655 cgm.errorNYI(expr->getSourceRange(),
2656 std::string("unimplemented AArch64 builtin call: ") +
2657 getContext().BuiltinInfo.getName(builtinID));
2658 return mlir::Value{};
2659 }
2660
2661 if (builtinID == AArch64::BI_CountOneBits ||
2662 builtinID == AArch64::BI_CountOneBits64 ||
2663 builtinID == AArch64::BI_CountTrailingZeros ||
2664 builtinID == AArch64::BI_CountTrailingZeros64) {
2665 cgm.errorNYI(expr->getSourceRange(),
2666 std::string("unimplemented AArch64 builtin call: ") +
2667 getContext().BuiltinInfo.getName(builtinID));
2668 return mlir::Value{};
2669 }
2670
2671 if (builtinID == AArch64::BI__prefetch ||
2672 builtinID == AArch64::BI__prefetch2) {
2673 cgm.errorNYI(expr->getSourceRange(),
2674 std::string("unimplemented AArch64 builtin call: ") +
2675 getContext().BuiltinInfo.getName(builtinID));
2676 return mlir::Value{};
2677 }
2678
2679 if (builtinID == AArch64::BI__hlt) {
2680 cgm.errorNYI(expr->getSourceRange(),
2681 std::string("unimplemented AArch64 builtin call: ") +
2682 getContext().BuiltinInfo.getName(builtinID));
2683 return mlir::Value{};
2684 }
2685
2686 if (builtinID == NEON::BI__builtin_neon_vcvth_bf16_f32) {
2687 cgm.errorNYI(expr->getSourceRange(),
2688 std::string("unimplemented AArch64 builtin call: ") +
2689 getContext().BuiltinInfo.getName(builtinID));
2690 return mlir::Value{};
2691 }
2692
2693 // Handle MSVC intrinsics before argument evaluation to prevent double
2694 // evaluation.
2696
2697 CIRGenFPOptionsRAII fpOptsRAII(*this, expr);
2698
2699 // Some intrinsics are equivalent - if they are use the base intrinsic ID.
2700 auto it = llvm::find_if(neonEquivalentIntrinsicMap, [builtinID](auto &p) {
2701 return p.first == builtinID;
2702 });
2703 if (it != end(neonEquivalentIntrinsicMap))
2704 builtinID = it->second;
2705
2706 // Find out if any arguments are required to be integer constant
2707 // expressions.
2709 unsigned iceArguments = 0;
2711 getContext().GetBuiltinType(builtinID, error, &iceArguments);
2712 assert(error == ASTContext::GE_None && "Should not codegen an error");
2714
2715 // Captures the pointer and its alignment for builtins that store/load
2716 // directly through the first argument, i.e. operand 0 (set in the
2717 // arg-gathering loop below, used later when lowering the store/load
2718 // itself).
2719 Address ptrOp0 = Address::invalid();
2720
2721 // Skip extra arguments used to discriminate vector types and that are
2722 // intended for Sema checking.
2723 bool hasExtraArg = CodeGenUtils::hasExtraNeonArgument(builtinID);
2724 unsigned numArgs = expr->getNumArgs() - (hasExtraArg ? 1 : 0);
2725 for (unsigned i = 0, e = numArgs; i != e; i++) {
2726 if (i == 0) {
2727 switch (builtinID) {
2728 case NEON::BI__builtin_neon_vld1_v:
2729 case NEON::BI__builtin_neon_vld1q_v:
2730 case NEON::BI__builtin_neon_vld1_dup_v:
2731 case NEON::BI__builtin_neon_vld1q_dup_v:
2732 case NEON::BI__builtin_neon_vld1_lane_v:
2733 case NEON::BI__builtin_neon_vld1q_lane_v:
2734 case NEON::BI__builtin_neon_vst1_v:
2735 case NEON::BI__builtin_neon_vst1q_v:
2736 case NEON::BI__builtin_neon_vst1_lane_v:
2737 case NEON::BI__builtin_neon_vst1q_lane_v:
2738 case NEON::BI__builtin_neon_vstrq_p128:
2739 case NEON::BI__builtin_neon_vst2_v:
2740 case NEON::BI__builtin_neon_vst2q_v:
2741 case NEON::BI__builtin_neon_vst2_lane_v:
2742 case NEON::BI__builtin_neon_vst2q_lane_v:
2743 case NEON::BI__builtin_neon_vst3_v:
2744 case NEON::BI__builtin_neon_vst3q_v:
2745 case NEON::BI__builtin_neon_vst3_lane_v:
2746 case NEON::BI__builtin_neon_vst3q_lane_v:
2747 case NEON::BI__builtin_neon_vst4_v:
2748 case NEON::BI__builtin_neon_vst4q_v:
2749 case NEON::BI__builtin_neon_vst4_lane_v:
2750 case NEON::BI__builtin_neon_vst4q_lane_v:
2751 // Get the alignment for the argument in addition to the value;
2752 // we'll use it later.
2753 ptrOp0 = emitPointerWithAlignment(expr->getArg(0));
2754 ops.push_back(ptrOp0.getPointer());
2755 continue;
2756 case NEON::BI__builtin_neon_vldap1_lane_s64:
2757 case NEON::BI__builtin_neon_vldap1q_lane_s64:
2758 case NEON::BI__builtin_neon_vstl1_lane_s64:
2759 case NEON::BI__builtin_neon_vstl1q_lane_s64:
2760 cgm.errorNYI(
2761 expr->getSourceRange(),
2762 std::string("unimplemented AArch64 builtin argument handling ") +
2763 getContext().BuiltinInfo.getName(builtinID));
2764 break;
2765 }
2766 }
2767 ops.push_back(
2768 emitScalarOrConstFoldImmArg(iceArguments, i, expr->getArg(i)));
2769 }
2770
2771 const ARMNeonVectorIntrinsicInfo *builtin =
2774 if (builtin)
2775 return emitCommonNeonSISDBuiltinExpr(*this, *builtin, ops, expr,
2776 iceArguments);
2777
2778 // Not all intrinsics handled by the common case work for AArch64 yet, so only
2779 // defer to common code if it's been added to our special map.
2781
2783
2784 const Expr *arg = expr->getArg(expr->getNumArgs() - 1);
2786 // A trailing constant integer is used for discriminating overloaded builtin
2787 // calls. Use it to determine the type of this overloaded NEON intrinsic.
2788 if (std::optional<llvm::APSInt> result =
2789 arg->getIntegerConstantExpr(getContext()))
2790 type = NeonTypeFlags(result->getZExtValue());
2791
2792 bool usgn = type.isUnsigned();
2793
2794 mlir::Location loc = getLoc(expr->getExprLoc());
2795
2796 // Not all intrinsics handled by the common case work for AArch64 yet, so only
2797 // defer to common code if it's been added to our special map.
2798 builtin =
2801 if (builtin)
2803 *this, builtin->BuiltinID, builtin->LLVMIntrinsic,
2804 builtin->AltLLVMIntrinsic, builtin->NameHint, builtin->TypeModifier,
2805 expr, ops);
2806
2807 // Handle non-overloaded intrinsics first.
2808 switch (builtinID) {
2809 default:
2810 break;
2811 case NEON::BI__builtin_neon_vabsh_f16: {
2812 mlir::Type halfTy = builder.getFp16Ty();
2813 return emitNeonCallToOp<cir::FAbsOp>(cgm, builder, {halfTy}, ops,
2814 std::nullopt, halfTy, loc);
2815 }
2816 case NEON::BI__builtin_neon_vaddq_p128: {
2817 cir::VectorType byteTy =
2818 cir::VectorType::getFixed(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::getFixed(cgm.floatTy, 4);
3151 auto v4f16 = cir::VectorType::getFixed(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::getFixed(cgm.floatTy, 4);
3157 auto v4f16 = cir::VectorType::getFixed(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::getFixed(
3205 ty.getElementType(), builtinID == NEON::BI__builtin_neon_vfmaq_lane_v
3206 ? ty.getFixedSize() / 2
3207 : ty.getFixedSize());
3208 mlir::Value laneSource = builder.createBitcast(ops[2], sourceTy);
3209 laneSource =
3210 emitNeonSplat(builder, loc, laneSource, ops[3], ty.getFixedSize());
3211
3212 llvm::SmallVector<mlir::Value> fmaOps = {multiplicand, laneSource, addend};
3213 return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, fmaOps,
3214 std::nullopt, ty, loc);
3215 }
3216 case NEON::BI__builtin_neon_vfma_laneq_v: {
3217 // v1f64 fma should be mapped to Neon scalar f64 fma.
3218 if (ty.getElementType() == cgm.doubleTy) {
3219 mlir::Value addend = builder.createBitcast(ops[0], cgm.doubleTy);
3220 mlir::Value multiplicand = builder.createBitcast(ops[1], cgm.doubleTy);
3221 // The laneq source operand is float64x2_t, so the source vector has two
3222 // double lanes.
3223 cir::VectorType sourceTy = cir::VectorType::getFixed(cgm.doubleTy, 2);
3224 mlir::Value laneSource = builder.createBitcast(ops[2], sourceTy);
3225 laneSource = builder.createExtractElement(
3226 loc, laneSource,
3227 static_cast<uint64_t>(getIntValueFromConstOp(ops[3])));
3228
3229 llvm::SmallVector<mlir::Value> fmaOps = {multiplicand, laneSource,
3230 addend};
3231 return builder.createBitcast(
3233 cgm, builder, {cgm.doubleTy, cgm.doubleTy, cgm.doubleTy}, fmaOps,
3234 std::nullopt, cgm.doubleTy, loc),
3235 ty);
3236 }
3237
3238 mlir::Value addend = builder.createBitcast(ops[0], ty);
3239 mlir::Value multiplicand = builder.createBitcast(ops[1], ty);
3240 // The laneq source operand is the quad vector, so it has twice as many
3241 // lanes as the non-quad result vector.
3242 cir::VectorType sourceTy =
3243 cir::VectorType::getFixed(ty.getElementType(), ty.getFixedSize() * 2);
3244 mlir::Value laneSource = builder.createBitcast(ops[2], sourceTy);
3245 laneSource =
3246 emitNeonSplat(builder, loc, laneSource, ops[3], ty.getFixedSize());
3247
3248 llvm::SmallVector<mlir::Value> fmaOps = {laneSource, multiplicand, addend};
3249 return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, fmaOps,
3250 std::nullopt, ty, loc);
3251 }
3252 case NEON::BI__builtin_neon_vfmaq_laneq_v: {
3253 mlir::Value addend = builder.createBitcast(ops[0], ty);
3254 mlir::Value multiplicand = builder.createBitcast(ops[1], ty);
3255 mlir::Value laneSource = builder.createBitcast(ops[2], ty);
3256 laneSource =
3257 emitNeonSplat(builder, loc, laneSource, ops[3], ty.getFixedSize());
3258
3259 llvm::SmallVector<mlir::Value> fmaOps = {laneSource, multiplicand, addend};
3260 return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, fmaOps,
3261 std::nullopt, ty, loc);
3262 }
3263 case NEON::BI__builtin_neon_vfmah_lane_f16:
3264 case NEON::BI__builtin_neon_vfmas_lane_f32:
3265 case NEON::BI__builtin_neon_vfmah_laneq_f16:
3266 case NEON::BI__builtin_neon_vfmas_laneq_f32: {
3267 // Scalar lane/laneq forms use one selected element from the lane source.
3268 mlir::Value laneSource = builder.createExtractElement(
3269 loc, ops[2], static_cast<uint64_t>(getIntValueFromConstOp(ops[3])));
3270
3271 llvm::SmallVector<mlir::Value> fmaOps = {ops[1], laneSource, ops[0]};
3272 mlir::Type ty = convertType(expr->getType());
3273 return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, fmaOps,
3274 std::nullopt, ty, loc);
3275 }
3276 case NEON::BI__builtin_neon_vfmad_lane_f64:
3277 case NEON::BI__builtin_neon_vfmad_laneq_f64: {
3278 // The lane source operand is float64x1_t for lane forms and float64x2_t
3279 // for laneq forms.
3280 mlir::Value laneSource = builder.createExtractElement(
3281 loc, ops[2], static_cast<uint64_t>(getIntValueFromConstOp(ops[3])));
3282
3283 llvm::SmallVector<mlir::Value> fmaOps = {ops[1], laneSource, ops[0]};
3285 cgm, builder, {cgm.doubleTy, cgm.doubleTy, cgm.doubleTy}, fmaOps,
3286 std::nullopt, cgm.doubleTy, loc);
3287 }
3288 case NEON::BI__builtin_neon_vmull_v: {
3289 intrName = usgn ? "aarch64.neon.umull" : "aarch64.neon.smull";
3290 if (type.isPoly())
3291 intrName = "aarch64.neon.pmull";
3292 cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
3293 ty, /*isExtended*/ false, !usgn);
3294 return emitNeonCall(cgm, builder, {argTy, argTy}, ops, intrName, ty, loc);
3295 }
3296 case NEON::BI__builtin_neon_vmax_v:
3297 case NEON::BI__builtin_neon_vmaxq_v:
3298 intrName = usgn ? "umax" : "smax";
3299 if (cir::isFPOrVectorOfFPType(ty))
3300 intrName = "aarch64.neon.fmax";
3301 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3302 case NEON::BI__builtin_neon_vmaxh_f16: {
3303 auto halfTy = builder.getFp16Ty();
3304 return builder.emitIntrinsicCallOp(loc, "aarch64.neon.fmax", halfTy, ops);
3305 }
3306 case NEON::BI__builtin_neon_vmin_v:
3307 case NEON::BI__builtin_neon_vminq_v:
3308 intrName = usgn ? "umin" : "smin";
3309 if (cir::isFPOrVectorOfFPType(ty))
3310 intrName = "aarch64.neon.fmin";
3311 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3312 case NEON::BI__builtin_neon_vminh_f16: {
3313 auto halfTy = builder.getFp16Ty();
3314 return builder.emitIntrinsicCallOp(loc, "aarch64.neon.fmin", halfTy, ops);
3315 }
3316 case NEON::BI__builtin_neon_vabd_v:
3317 case NEON::BI__builtin_neon_vabdq_v:
3318 intrName = usgn ? "aarch64.neon.uabd" : "aarch64.neon.sabd";
3319 if (cir::isFPOrVectorOfFPType(ty))
3320 intrName = "aarch64.neon.fabd";
3321 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3322 case NEON::BI__builtin_neon_vpadal_v:
3323 case NEON::BI__builtin_neon_vpadalq_v: {
3324 intrName = usgn ? "aarch64.neon.uaddlp" : "aarch64.neon.saddlp";
3325 llvm::SmallVector<mlir::Value> inputs{ops[1]};
3326 mlir::Value pairwiseSum =
3327 emitNeonCall(cgm, builder, {getNeonPairwiseWidenInputType(ty, usgn)},
3328 inputs, intrName, ty, loc);
3329 mlir::Value accumValue = builder.createBitcast(loc, ops[0], ty);
3330 return cir::AddOp::create(builder, loc, ty, pairwiseSum, accumValue);
3331 }
3332 case NEON::BI__builtin_neon_vpmin_v:
3333 case NEON::BI__builtin_neon_vpminq_v:
3334 intrName = usgn ? "aarch64.neon.uminp" : "aarch64.neon.sminp";
3335 if (cir::isFPOrVectorOfFPType(ty))
3336 intrName = "aarch64.neon.fminp";
3337 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3338 case NEON::BI__builtin_neon_vpmax_v:
3339 case NEON::BI__builtin_neon_vpmaxq_v:
3340 intrName = usgn ? "aarch64.neon.umaxp" : "aarch64.neon.smaxp";
3341 if (cir::isFPOrVectorOfFPType(ty))
3342 intrName = "aarch64.neon.fmaxp";
3343 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3344 case NEON::BI__builtin_neon_vminnm_v:
3345 case NEON::BI__builtin_neon_vminnmq_v:
3346 intrName = "aarch64.neon.fminnm";
3347 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3348 case NEON::BI__builtin_neon_vminnmh_f16: {
3349 auto halfTy = builder.getFp16Ty();
3350 return builder.emitIntrinsicCallOp(loc, "aarch64.neon.fminnm", halfTy, ops);
3351 }
3352 case NEON::BI__builtin_neon_vmaxnm_v:
3353 case NEON::BI__builtin_neon_vmaxnmq_v:
3354 intrName = "aarch64.neon.fmaxnm";
3355 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3356 case NEON::BI__builtin_neon_vmaxnmh_f16: {
3357 auto halfTy = builder.getFp16Ty();
3358 return builder.emitIntrinsicCallOp(loc, "aarch64.neon.fmaxnm", halfTy, ops);
3359 }
3360 case NEON::BI__builtin_neon_vrecpss_f32:
3361 case NEON::BI__builtin_neon_vrecpsd_f64:
3362 cgm.errorNYI(expr->getSourceRange(),
3363 std::string("unimplemented AArch64 builtin call: ") +
3364 getContext().BuiltinInfo.getName(builtinID));
3365 return mlir::Value{};
3366 case NEON::BI__builtin_neon_vrecpsh_f16: {
3367 auto halfTy = builder.getFp16Ty();
3368 return builder.emitIntrinsicCallOp(loc, "aarch64.neon.frecps", halfTy, ops);
3369 }
3370 case NEON::BI__builtin_neon_vqshrun_n_v: {
3371 cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
3372 ty, /*isExtended=*/true, /*isSigned=*/true);
3373 return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops,
3374 "aarch64.neon.sqshrun", ty, loc);
3375 }
3376 case NEON::BI__builtin_neon_vqrshrun_n_v: {
3377 cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
3378 ty, /*isExtended=*/true, /*isSigned=*/true);
3379 return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops,
3380 "aarch64.neon.sqrshrun", ty, loc);
3381 }
3382 case NEON::BI__builtin_neon_vqshrn_n_v: {
3383 cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
3384 ty, /*isExtended=*/true, /*isSigned=*/!usgn);
3385 llvm::StringRef intrName =
3386 usgn ? "aarch64.neon.uqshrn" : "aarch64.neon.sqshrn";
3387 return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops, intrName, ty,
3388 loc);
3389 }
3390 case NEON::BI__builtin_neon_vrshrn_n_v:
3391 cgm.errorNYI(expr->getSourceRange(),
3392 std::string("unimplemented AArch64 builtin call: ") +
3393 getContext().BuiltinInfo.getName(builtinID));
3394 return mlir::Value{};
3395 case NEON::BI__builtin_neon_vqrshrn_n_v: {
3396 cir::VectorType argTy = builder.getExtendedOrTruncatedElementVectorType(
3397 ty, /*isExtended=*/true, /*isSigned=*/!usgn);
3398 llvm::StringRef intrName =
3399 usgn ? "aarch64.neon.uqrshrn" : "aarch64.neon.sqrshrn";
3400 return emitNeonCall(cgm, builder, {argTy, sInt32Ty}, ops, intrName, ty,
3401 loc);
3402 }
3403 case NEON::BI__builtin_neon_vrndah_f16: {
3405 mlir::Type halfTy = builder.getFp16Ty();
3406 return emitNeonCallToOp<cir::RoundOp>(cgm, builder, {halfTy}, ops,
3407 std::nullopt, halfTy, loc);
3408 }
3409 case NEON::BI__builtin_neon_vrnda_v:
3410 case NEON::BI__builtin_neon_vrndaq_v:
3412 return emitNeonCallToOp<cir::RoundOp>(cgm, builder, {ty}, ops, std::nullopt,
3413 ty, loc);
3414 case NEON::BI__builtin_neon_vrndih_f16: {
3416 mlir::Type halfTy = builder.getFp16Ty();
3417 return emitNeonCallToOp<cir::NearbyintOp>(cgm, builder, {halfTy}, ops,
3418 std::nullopt, halfTy, loc);
3419 }
3420 case NEON::BI__builtin_neon_vrndmh_f16: {
3422 mlir::Type halfTy = builder.getFp16Ty();
3423 return emitNeonCallToOp<cir::FloorOp>(cgm, builder, {halfTy}, ops,
3424 std::nullopt, halfTy, loc);
3425 }
3426 case NEON::BI__builtin_neon_vrndm_v:
3427 case NEON::BI__builtin_neon_vrndmq_v:
3429 return emitNeonCallToOp<cir::FloorOp>(cgm, builder, {ty}, ops, std::nullopt,
3430 ty, loc);
3431 case NEON::BI__builtin_neon_vrndnh_f16: {
3433 mlir::Type halfTy = builder.getFp16Ty();
3434 return emitNeonCallToOp<cir::RoundEvenOp>(cgm, builder, {halfTy}, ops,
3435 std::nullopt, halfTy, loc);
3436 }
3437 case NEON::BI__builtin_neon_vrndn_v:
3438 case NEON::BI__builtin_neon_vrndnq_v:
3440 return emitNeonCallToOp<cir::RoundEvenOp>(cgm, builder, {ty}, ops,
3441 std::nullopt, ty, loc);
3442 case NEON::BI__builtin_neon_vrndns_f32: {
3444 mlir::Type floatTy = builder.getSingleTy();
3445 return emitNeonCallToOp<cir::RoundEvenOp>(cgm, builder, {floatTy}, ops,
3446 std::nullopt, floatTy, loc);
3447 }
3448 case NEON::BI__builtin_neon_vrndph_f16: {
3450 mlir::Type halfTy = builder.getFp16Ty();
3451 return emitNeonCallToOp<cir::CeilOp>(cgm, builder, {halfTy}, ops,
3452 std::nullopt, halfTy, loc);
3453 }
3454 case NEON::BI__builtin_neon_vrndp_v:
3455 case NEON::BI__builtin_neon_vrndpq_v:
3457 return emitNeonCallToOp<cir::CeilOp>(cgm, builder, {ty}, ops, std::nullopt,
3458 ty, loc);
3459 case NEON::BI__builtin_neon_vrndxh_f16: {
3461 mlir::Type halfTy = builder.getFp16Ty();
3462 return emitNeonCallToOp<cir::RintOp>(cgm, builder, {halfTy}, ops,
3463 std::nullopt, halfTy, loc);
3464 }
3465 case NEON::BI__builtin_neon_vrndx_v:
3466 case NEON::BI__builtin_neon_vrndxq_v:
3468 return emitNeonCallToOp<cir::RintOp>(cgm, builder, {ty}, ops, std::nullopt,
3469 ty, loc);
3470 case NEON::BI__builtin_neon_vrndh_f16: {
3472 mlir::Type halfTy = builder.getFp16Ty();
3473 return emitNeonCallToOp<cir::TruncOp>(cgm, builder, {halfTy}, ops,
3474 std::nullopt, halfTy, loc);
3475 }
3476 case NEON::BI__builtin_neon_vrnd_v:
3477 case NEON::BI__builtin_neon_vrndq_v:
3479 return emitNeonCallToOp<cir::TruncOp>(cgm, builder, {ty}, ops, std::nullopt,
3480 ty, loc);
3481 case NEON::BI__builtin_neon_vcvt_f64_v:
3482 case NEON::BI__builtin_neon_vcvtq_f64_v:
3483 ops[0] = builder.createBitcast(ops[0], ty);
3484 ty = getNeonType(
3485 this, NeonTypeFlags(NeonTypeFlags::Float64, false, type.isQuad()));
3486 return builder.createCast(loc, cir::CastKind::int_to_float, ops[0], ty);
3487 case NEON::BI__builtin_neon_vcvt_f64_f32: {
3488 auto v2f32 = cir::VectorType::getFixed(cgm.floatTy, 2);
3489 auto v2f64 = cir::VectorType::getFixed(cgm.doubleTy, 2);
3490 return builder.createFloatingCast(builder.createBitcast(ops[0], v2f32),
3491 v2f64);
3492 }
3493 case NEON::BI__builtin_neon_vcvt_f32_f64: {
3494 auto v2f32 = cir::VectorType::getFixed(cgm.floatTy, 2);
3495 auto v2f64 = cir::VectorType::getFixed(cgm.doubleTy, 2);
3496 return builder.createFloatingCast(builder.createBitcast(ops[0], v2f64),
3497 v2f32);
3498 }
3499 case NEON::BI__builtin_neon_vcvt_s32_v:
3500 case NEON::BI__builtin_neon_vcvt_u32_v:
3501 case NEON::BI__builtin_neon_vcvt_s64_v:
3502 case NEON::BI__builtin_neon_vcvt_u64_v:
3503 case NEON::BI__builtin_neon_vcvt_s16_f16:
3504 case NEON::BI__builtin_neon_vcvt_u16_f16:
3505 case NEON::BI__builtin_neon_vcvtq_s32_v:
3506 case NEON::BI__builtin_neon_vcvtq_u32_v:
3507 case NEON::BI__builtin_neon_vcvtq_s64_v:
3508 case NEON::BI__builtin_neon_vcvtq_u64_v:
3509 case NEON::BI__builtin_neon_vcvtq_s16_f16:
3510 case NEON::BI__builtin_neon_vcvtq_u16_f16:
3511
3512 case NEON::BI__builtin_neon_vcvta_s16_f16:
3513 case NEON::BI__builtin_neon_vcvta_u16_f16:
3514 case NEON::BI__builtin_neon_vcvtaq_s16_f16:
3515 case NEON::BI__builtin_neon_vcvtaq_u16_f16:
3516 cgm.errorNYI(expr->getSourceRange(),
3517 std::string("unimplemented AArch64 builtin call: ") +
3518 getContext().BuiltinInfo.getName(builtinID));
3519 return mlir::Value{};
3520 case NEON::BI__builtin_neon_vcvta_s32_v:
3521 case NEON::BI__builtin_neon_vcvtaq_s32_v:
3522 case NEON::BI__builtin_neon_vcvta_u32_v:
3523 case NEON::BI__builtin_neon_vcvtaq_u32_v:
3524 case NEON::BI__builtin_neon_vcvta_s64_v:
3525 case NEON::BI__builtin_neon_vcvtaq_s64_v:
3526 case NEON::BI__builtin_neon_vcvta_u64_v:
3527 case NEON::BI__builtin_neon_vcvtaq_u64_v: {
3528 auto argTy = getFloatNeonType(*this, type);
3529 llvm::StringRef intrName =
3530 usgn ? "aarch64.neon.fcvtau" : "aarch64.neon.fcvtas";
3531 return emitNeonCall(cgm, builder, {argTy}, ops, intrName, ty, loc);
3532 }
3533
3534 case NEON::BI__builtin_neon_vcvtm_s16_f16:
3535 case NEON::BI__builtin_neon_vcvtmq_s16_f16:
3536 case NEON::BI__builtin_neon_vcvtm_u16_f16:
3537 case NEON::BI__builtin_neon_vcvtmq_u16_f16:
3538 cgm.errorNYI(expr->getSourceRange(),
3539 std::string("unimplemented AArch64 builtin call: ") +
3540 getContext().BuiltinInfo.getName(builtinID));
3541 return mlir::Value{};
3542 case NEON::BI__builtin_neon_vcvtm_s32_v:
3543 case NEON::BI__builtin_neon_vcvtmq_s32_v:
3544 case NEON::BI__builtin_neon_vcvtm_u32_v:
3545 case NEON::BI__builtin_neon_vcvtmq_u32_v:
3546 case NEON::BI__builtin_neon_vcvtm_s64_v:
3547 case NEON::BI__builtin_neon_vcvtmq_s64_v:
3548 case NEON::BI__builtin_neon_vcvtm_u64_v:
3549 case NEON::BI__builtin_neon_vcvtmq_u64_v: {
3550 auto argTy = getFloatNeonType(*this, type);
3551 llvm::StringRef intrName =
3552 usgn ? "aarch64.neon.fcvtmu" : "aarch64.neon.fcvtms";
3553 return emitNeonCall(cgm, builder, {argTy}, ops, intrName, ty, loc);
3554 }
3555
3556 case NEON::BI__builtin_neon_vcvtn_s16_f16:
3557 case NEON::BI__builtin_neon_vcvtnq_s16_f16:
3558 case NEON::BI__builtin_neon_vcvtn_u16_f16:
3559 case NEON::BI__builtin_neon_vcvtnq_u16_f16:
3560 cgm.errorNYI(expr->getSourceRange(),
3561 std::string("unimplemented AArch64 builtin call: ") +
3562 getContext().BuiltinInfo.getName(builtinID));
3563 return mlir::Value{};
3564
3565 case NEON::BI__builtin_neon_vcvtn_s32_v:
3566 case NEON::BI__builtin_neon_vcvtnq_s32_v:
3567 case NEON::BI__builtin_neon_vcvtn_u32_v:
3568 case NEON::BI__builtin_neon_vcvtnq_u32_v:
3569 case NEON::BI__builtin_neon_vcvtn_s64_v:
3570 case NEON::BI__builtin_neon_vcvtnq_s64_v:
3571 case NEON::BI__builtin_neon_vcvtn_u64_v:
3572 case NEON::BI__builtin_neon_vcvtnq_u64_v: {
3573 auto argTy = getFloatNeonType(*this, type);
3574 llvm::StringRef intrName =
3575 usgn ? "aarch64.neon.fcvtnu" : "aarch64.neon.fcvtns";
3576 return emitNeonCall(cgm, builder, {argTy}, ops, intrName, ty, loc);
3577 }
3578
3579 case NEON::BI__builtin_neon_vcvtp_s16_f16:
3580 case NEON::BI__builtin_neon_vcvtpq_s16_f16:
3581 case NEON::BI__builtin_neon_vcvtp_u16_f16:
3582 case NEON::BI__builtin_neon_vcvtpq_u16_f16:
3583 cgm.errorNYI(expr->getSourceRange(),
3584 std::string("unimplemented AArch64 builtin call: ") +
3585 getContext().BuiltinInfo.getName(builtinID));
3586 return mlir::Value{};
3587 case NEON::BI__builtin_neon_vcvtp_s32_v:
3588 case NEON::BI__builtin_neon_vcvtpq_s32_v:
3589 case NEON::BI__builtin_neon_vcvtp_u32_v:
3590 case NEON::BI__builtin_neon_vcvtpq_u32_v:
3591 case NEON::BI__builtin_neon_vcvtp_s64_v:
3592 case NEON::BI__builtin_neon_vcvtpq_s64_v:
3593 case NEON::BI__builtin_neon_vcvtp_u64_v:
3594 case NEON::BI__builtin_neon_vcvtpq_u64_v: {
3595 auto argTy = getFloatNeonType(*this, type);
3596 llvm::StringRef intrName =
3597 usgn ? "aarch64.neon.fcvtpu" : "aarch64.neon.fcvtps";
3598 return emitNeonCall(cgm, builder, {argTy}, ops, intrName, ty, loc);
3599 }
3600
3601 case NEON::BI__builtin_neon_vmulx_v:
3602 case NEON::BI__builtin_neon_vmulxq_v:
3603 case NEON::BI__builtin_neon_vmulxh_lane_f16:
3604 case NEON::BI__builtin_neon_vmulxh_laneq_f16:
3605 case NEON::BI__builtin_neon_vmul_lane_v:
3606 case NEON::BI__builtin_neon_vmul_laneq_v:
3607 case NEON::BI__builtin_neon_vpmaxnm_v:
3608 case NEON::BI__builtin_neon_vpmaxnmq_v:
3609 cgm.errorNYI(expr->getSourceRange(),
3610 std::string("unimplemented AArch64 builtin call: ") +
3611 getContext().BuiltinInfo.getName(builtinID));
3612 return mlir::Value{};
3613 case NEON::BI__builtin_neon_vpminnm_v:
3614 case NEON::BI__builtin_neon_vpminnmq_v:
3615 intrName = "aarch64.neon.fminnmp";
3616 return emitNeonCall(cgm, builder, {ty, ty}, ops, intrName, ty, loc);
3617 case NEON::BI__builtin_neon_vsqrth_f16: {
3618 mlir::Type halfTy = builder.getFp16Ty();
3619 return emitNeonCallToOp<cir::SqrtOp>(cgm, builder, {halfTy}, ops,
3620 std::nullopt, halfTy, loc);
3621 }
3622 case NEON::BI__builtin_neon_vsqrt_v:
3623 case NEON::BI__builtin_neon_vsqrtq_v:
3624 return emitNeonCallToOp<cir::SqrtOp>(cgm, builder, {ty}, ops, std::nullopt,
3625 ty, loc);
3626 case NEON::BI__builtin_neon_vrbit_v:
3627 case NEON::BI__builtin_neon_vrbitq_v:
3628 case NEON::BI__builtin_neon_vmaxv_f16:
3629 case NEON::BI__builtin_neon_vmaxvq_f16:
3630 case NEON::BI__builtin_neon_vminv_f16:
3631 case NEON::BI__builtin_neon_vminvq_f16:
3632 case NEON::BI__builtin_neon_vmaxnmv_f16:
3633 case NEON::BI__builtin_neon_vmaxnmvq_f16:
3634 case NEON::BI__builtin_neon_vminnmv_f16:
3635 case NEON::BI__builtin_neon_vminnmvq_f16:
3636 case NEON::BI__builtin_neon_vmul_n_f64:
3637 cgm.errorNYI(expr->getSourceRange(),
3638 std::string("unimplemented AArch64 builtin call: ") +
3639 getContext().BuiltinInfo.getName(builtinID));
3640 return mlir::Value{};
3641 case NEON::BI__builtin_neon_vaddlv_u8:
3642 case NEON::BI__builtin_neon_vaddlvq_u8:
3643 case NEON::BI__builtin_neon_vaddlv_u16:
3644 case NEON::BI__builtin_neon_vaddlvq_u16:
3645 case NEON::BI__builtin_neon_vaddlv_s8:
3646 case NEON::BI__builtin_neon_vaddlvq_s8:
3647 case NEON::BI__builtin_neon_vaddlv_s16:
3648 case NEON::BI__builtin_neon_vaddlvq_s16: {
3649 mlir::Type argTy = convertType(expr->getArg(0)->getType());
3650 mlir::Type userRetTy = convertType(expr->getType());
3651 auto eltTy = mlir::cast<cir::IntType>(
3652 mlir::cast<cir::VectorType>(argTy).getElementType());
3653 bool isUnsigned = !eltTy.isSigned();
3654 // These builtins only use 8 and 16-bit element vectors; the intrinsic
3655 // always produces i32. The C result is i32 for 16-bit elements, but i16
3656 // for 8-bit elements, so we emit at i32 and narrow only in that case.
3657 bool needsTrunc = eltTy.getWidth() == 8;
3658 intrName = isUnsigned ? "aarch64.neon.uaddlv" : "aarch64.neon.saddlv";
3659 mlir::Type intrRetTy = userRetTy;
3660 if (needsTrunc)
3661 intrRetTy = isUnsigned ? builder.getUInt32Ty() : builder.getSInt32Ty();
3662 mlir::Value result =
3663 emitNeonCall(cgm, builder, {argTy}, ops, intrName, intrRetTy, loc);
3664 if (needsTrunc)
3665 result = builder.createIntCast(result, userRetTy);
3666 return result;
3667 }
3668 case NEON::BI__builtin_neon_vsri_n_v:
3669 case NEON::BI__builtin_neon_vsriq_n_v: {
3671 ops[0], ops[1], builder.createIntCast(ops[2], builder.getUInt32Ty())};
3672 return emitNeonCall(cgm, builder, {ty, ty, builder.getUInt32Ty()}, vsriArgs,
3673 "aarch64.neon.vsri", ty, loc);
3674 }
3675 case NEON::BI__builtin_neon_vsli_n_v:
3676 case NEON::BI__builtin_neon_vsliq_n_v: {
3677
3678 intrName = "aarch64.neon.vsli";
3679
3680 llvm::SmallVector<mlir::Type> argTypes = {ty, ty, ops[2].getType()};
3681
3682 return emitNeonCall(cgm, builder, argTypes, ops, intrName, ty, loc,
3683 /*isConstrainedFPIntrinsic=*/false,
3684 /*shift=*/0, /*rightshift=*/false);
3685 }
3686 case NEON::BI__builtin_neon_vsra_n_v:
3687 case NEON::BI__builtin_neon_vsraq_n_v: {
3688 ops[0] = builder.createBitcast(ops[0], ty);
3689 ops[1] = emitNeonRShiftImm(*this, ops[1], ops[2], ty, usgn, loc);
3690 return builder.createAdd(loc, ops[0], ops[1]);
3691 }
3692 case NEON::BI__builtin_neon_vrsra_n_v:
3693 case NEON::BI__builtin_neon_vrsraq_n_v: {
3694 intrName = usgn ? "aarch64.neon.urshl" : "aarch64.neon.srshl";
3695 // The llvm intrinsic is expecting negative shift amount for right shift.
3696 // Thus we have to make shift amount vec type to be signed.
3697 cir::VectorType shiftAmtVecTy =
3698 usgn ? getSignChangedVectorType(builder, ty) : ty;
3699 llvm::SmallVector<mlir::Value, 2> tmpOps = {ops[1], ops[2]};
3700 mlir::Value tmp = emitNeonCall(cgm, builder, {ty, shiftAmtVecTy}, tmpOps,
3701 intrName, ty, loc,
3702 /*isConstrainedFPIntrinsic=*/false,
3703 /*shift=*/1, /*rightshift=*/true);
3704 ops[0] = builder.createBitcast(ops[0], ty);
3705 return builder.createAdd(loc, ops[0], tmp);
3706 }
3707 case NEON::BI__builtin_neon_vld1_v:
3708 case NEON::BI__builtin_neon_vld1q_v:
3709 return builder.createLoad(loc, ptrOp0.withElementType(builder, ty));
3710 case NEON::BI__builtin_neon_vst1_v:
3711 case NEON::BI__builtin_neon_vst1q_v: {
3712 ops[1] = builder.createBitcast(ops[1], ty);
3713 builder.createStore(loc, ops[1], ptrOp0.withElementType(builder, ty));
3714 return nullptr;
3715 }
3716 case NEON::BI__builtin_neon_vld1_lane_v:
3717 case NEON::BI__builtin_neon_vld1q_lane_v: {
3718 ops[1] = builder.createBitcast(ops[1], ty);
3719 mlir::Value scalar = builder.createLoad(
3720 loc, ptrOp0.withElementType(builder, ty.getElementType()));
3721 return cir::VecInsertOp::create(builder, loc, ops[1], scalar, ops[2]);
3722 }
3723 case NEON::BI__builtin_neon_vld1_dup_v:
3724 case NEON::BI__builtin_neon_vld1q_dup_v: {
3725 mlir::Value scalar = builder.createLoad(
3726 loc, ptrOp0.withElementType(builder, ty.getElementType()));
3727 return cir::VecSplatOp::create(builder, loc, ty, scalar);
3728 }
3729 case NEON::BI__builtin_neon_vldap1_lane_s64:
3730 case NEON::BI__builtin_neon_vldap1q_lane_s64:
3731 cgm.errorNYI(expr->getSourceRange(),
3732 std::string("unimplemented AArch64 builtin call: ") +
3733 getContext().BuiltinInfo.getName(builtinID));
3734 return mlir::Value{};
3735 case NEON::BI__builtin_neon_vst1_lane_v:
3736 case NEON::BI__builtin_neon_vst1q_lane_v: {
3737 ops[1] = builder.createBitcast(ops[1], ty);
3738 mlir::Value scalar = builder.createExtractElement(
3739 loc, ops[1], static_cast<uint64_t>(getIntValueFromConstOp(ops[2])));
3740 builder.createStore(loc, scalar,
3741 ptrOp0.withElementType(builder, scalar.getType()));
3742 return nullptr;
3743 }
3744 case NEON::BI__builtin_neon_vstl1_lane_s64:
3745 case NEON::BI__builtin_neon_vstl1q_lane_s64:
3746 cgm.errorNYI(expr->getSourceRange(),
3747 std::string("unimplemented AArch64 builtin call: ") +
3748 getContext().BuiltinInfo.getName(builtinID));
3749 return mlir::Value{};
3750 case NEON::BI__builtin_neon_vld2_v:
3751 case NEON::BI__builtin_neon_vld2q_v:
3752 return emitNeonMultiVecLoad(*this, ops, llvm::Intrinsic::aarch64_neon_ld2,
3753 ty, 2, loc);
3754 case NEON::BI__builtin_neon_vld3_v:
3755 case NEON::BI__builtin_neon_vld3q_v:
3756 return emitNeonMultiVecLoad(*this, ops, llvm::Intrinsic::aarch64_neon_ld3,
3757 ty, 3, loc);
3758 case NEON::BI__builtin_neon_vld4_v:
3759 case NEON::BI__builtin_neon_vld4q_v:
3760 return emitNeonMultiVecLoad(*this, ops, llvm::Intrinsic::aarch64_neon_ld4,
3761 ty, 4, loc);
3762 case NEON::BI__builtin_neon_vld2_dup_v:
3763 case NEON::BI__builtin_neon_vld2q_dup_v:
3764 return emitNeonMultiVecLoad(*this, ops, llvm::Intrinsic::aarch64_neon_ld2r,
3765 ty, 2, loc);
3766 case NEON::BI__builtin_neon_vld3_dup_v:
3767 case NEON::BI__builtin_neon_vld3q_dup_v:
3768 return emitNeonMultiVecLoad(*this, ops, llvm::Intrinsic::aarch64_neon_ld3r,
3769 ty, 3, loc);
3770 case NEON::BI__builtin_neon_vld4_dup_v:
3771 case NEON::BI__builtin_neon_vld4q_dup_v:
3772 return emitNeonMultiVecLoad(*this, ops, llvm::Intrinsic::aarch64_neon_ld4r,
3773 ty, 4, loc);
3774 case NEON::BI__builtin_neon_vld2_lane_v:
3775 case NEON::BI__builtin_neon_vld2q_lane_v:
3777 *this, ops, llvm::Intrinsic::aarch64_neon_ld2lane, ty, 2, loc);
3778 case NEON::BI__builtin_neon_vld3_lane_v:
3779 case NEON::BI__builtin_neon_vld3q_lane_v:
3781 *this, ops, llvm::Intrinsic::aarch64_neon_ld3lane, ty, 3, loc);
3782 case NEON::BI__builtin_neon_vld4_lane_v:
3783 case NEON::BI__builtin_neon_vld4q_lane_v:
3785 *this, ops, llvm::Intrinsic::aarch64_neon_ld4lane, ty, 4, loc);
3786 case NEON::BI__builtin_neon_vst2_v:
3787 case NEON::BI__builtin_neon_vst2q_v: {
3788 // The builtin call has the pointer first, but the AArch64 st2 intrinsic
3789 // takes the vector operands first and the pointer last.
3790 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3791 llvm::SmallVector<mlir::Type> argTypes = {ty, ty, builder.getVoidPtrTy()};
3792 return emitNeonCall(cgm, builder, argTypes, ops, "aarch64.neon.st2",
3793 cgm.voidTy, loc);
3794 }
3795 case NEON::BI__builtin_neon_vst2_lane_v:
3796 case NEON::BI__builtin_neon_vst2q_lane_v: {
3797 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3798 ops[2] = builder.createIntCast(ops[2], sInt64Ty);
3799 llvm::SmallVector<mlir::Type> argTypes = {ty, ty, sInt64Ty,
3800 builder.getVoidPtrTy()};
3801 return emitNeonCall(cgm, builder, argTypes, ops, "aarch64.neon.st2lane",
3802 cgm.voidTy, loc);
3803 }
3804 case NEON::BI__builtin_neon_vst3_v:
3805 case NEON::BI__builtin_neon_vst3q_v: {
3806 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3807 llvm::SmallVector<mlir::Type> argTypes = {ty, ty, ty,
3808 builder.getVoidPtrTy()};
3809 return emitNeonCall(cgm, builder, argTypes, ops, "aarch64.neon.st3",
3810 cgm.voidTy, loc);
3811 }
3812 case NEON::BI__builtin_neon_vst3_lane_v:
3813 case NEON::BI__builtin_neon_vst3q_lane_v: {
3814 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3815 ops[3] = builder.createIntCast(ops[3], sInt64Ty);
3816 llvm::SmallVector<mlir::Type> argTypes = {ty, ty, ty, sInt64Ty,
3817 builder.getVoidPtrTy()};
3818 return emitNeonCall(cgm, builder, argTypes, ops, "aarch64.neon.st3lane",
3819 cgm.voidTy, loc);
3820 }
3821 case NEON::BI__builtin_neon_vst4_v:
3822 case NEON::BI__builtin_neon_vst4q_v: {
3823 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3824 llvm::SmallVector<mlir::Type> argTypes = {ty, ty, ty, ty,
3825 builder.getVoidPtrTy()};
3826 return emitNeonCall(cgm, builder, argTypes, ops, "aarch64.neon.st4",
3827 cgm.voidTy, loc);
3828 }
3829 case NEON::BI__builtin_neon_vst4_lane_v:
3830 case NEON::BI__builtin_neon_vst4q_lane_v: {
3831 std::rotate(ops.begin(), ops.begin() + 1, ops.end());
3832 ops[4] = builder.createIntCast(ops[4], sInt64Ty);
3834 ty, ty, ty, ty, sInt64Ty, builder.getVoidPtrTy()};
3835 return emitNeonCall(cgm, builder, argTypes, ops, "aarch64.neon.st4lane",
3836 cgm.voidTy, loc);
3837 }
3838 case NEON::BI__builtin_neon_vtrn_v:
3839 case NEON::BI__builtin_neon_vtrnq_v: {
3840 ops[1] = builder.createBitcast(ops[1], ty);
3841 ops[2] = builder.createBitcast(ops[2], ty);
3842 // Adding a bitcast here as Ops[0] might be a void pointer.
3843 mlir::Value baseAddr =
3844 builder.createBitcast(ops[0], builder.getPointerTo(ty));
3845 mlir::Value sv;
3846
3847 for (unsigned vi = 0; vi != 2; ++vi) {
3849 for (unsigned i = 0, e = ty.getFixedSize(); i != e; i += 2) {
3850 indices.push_back(i + vi);
3851 indices.push_back(i + e + vi);
3852 }
3853 cir::ConstantOp idx = builder.getConstInt(loc, builder.getSInt32Ty(), vi);
3854 mlir::Value addr = builder.createPtrStride(loc, baseAddr, idx);
3855 sv = builder.createVecShuffle(loc, ops[1], ops[2], indices);
3856 (void)builder.CIRBaseBuilderTy::createStore(loc, sv, addr);
3857 }
3858 return sv;
3859 }
3860 case NEON::BI__builtin_neon_vuzp_v:
3861 case NEON::BI__builtin_neon_vuzpq_v: {
3862 ops[1] = builder.createBitcast(ops[1], ty);
3863 ops[2] = builder.createBitcast(ops[2], ty);
3864 // Adding a bitcast here as Ops[0] might be a void pointer.
3865 mlir::Value baseAddr =
3866 builder.createBitcast(ops[0], builder.getPointerTo(ty));
3867 mlir::Value sv;
3868 for (unsigned vi = 0; vi != 2; ++vi) {
3870 for (unsigned i = 0, e = ty.getFixedSize(); i != e; ++i) {
3871 indices.push_back(2 * i + vi);
3872 }
3873 cir::ConstantOp idx = builder.getConstInt(loc, builder.getSInt32Ty(), vi);
3874 mlir::Value addr = builder.createPtrStride(loc, baseAddr, idx);
3875 sv = builder.createVecShuffle(loc, ops[1], ops[2], indices);
3876 (void)builder.CIRBaseBuilderTy::createStore(loc, sv, addr);
3877 }
3878 return sv;
3879 }
3880 case NEON::BI__builtin_neon_vzip_v:
3881 case NEON::BI__builtin_neon_vzipq_v: {
3882 ops[1] = builder.createBitcast(ops[1], ty);
3883 ops[2] = builder.createBitcast(ops[2], ty);
3884 // Adding a bitcast here as Ops[0] might be a void pointer.
3885 mlir::Value baseAddr =
3886 builder.createBitcast(ops[0], builder.getPointerTo(ty));
3887 mlir::Value sv;
3888 for (unsigned vi = 0; vi != 2; ++vi) {
3890 for (unsigned i = 0, e = ty.getFixedSize(); i != e; i += 2) {
3891 indices.push_back((i + vi * e) >> 1);
3892 indices.push_back(((i + vi * e) >> 1) + e);
3893 }
3894 cir::ConstantOp idx = builder.getConstInt(loc, builder.getSInt32Ty(), vi);
3895 mlir::Value addr = builder.createPtrStride(loc, baseAddr, idx);
3896 sv = builder.createVecShuffle(loc, ops[1], ops[2], indices);
3897 (void)builder.CIRBaseBuilderTy::createStore(loc, sv, addr);
3898 }
3899 return sv;
3900 }
3901 case NEON::BI__builtin_neon_vqtbl1q_v:
3902 case NEON::BI__builtin_neon_vqtbl2q_v:
3903 case NEON::BI__builtin_neon_vqtbl3q_v:
3904 case NEON::BI__builtin_neon_vqtbl4q_v:
3905 case NEON::BI__builtin_neon_vqtbx1q_v:
3906 case NEON::BI__builtin_neon_vqtbx2q_v:
3907 case NEON::BI__builtin_neon_vqtbx3q_v:
3908 case NEON::BI__builtin_neon_vqtbx4q_v:
3909 cgm.errorNYI(expr->getSourceRange(),
3910 std::string("unimplemented AArch64 builtin call: ") +
3911 getContext().BuiltinInfo.getName(builtinID));
3912 return mlir::Value{};
3913 case NEON::BI__builtin_neon_vsqadd_v:
3914 case NEON::BI__builtin_neon_vsqaddq_v:
3915 return emitNeonCall(cgm, builder, {ty, ty}, ops, "aarch64.neon.usqadd", ty,
3916 loc);
3917 case NEON::BI__builtin_neon_vuqadd_v:
3918 case NEON::BI__builtin_neon_vuqaddq_v:
3919 return emitNeonCall(cgm, builder, {ty, ty}, ops, "aarch64.neon.suqadd", ty,
3920 loc);
3921 case NEON::BI__builtin_neon_vluti2_laneq_mf8:
3922 case NEON::BI__builtin_neon_vluti2_laneq_bf16:
3923 case NEON::BI__builtin_neon_vluti2_laneq_f16:
3924 case NEON::BI__builtin_neon_vluti2_laneq_p16:
3925 case NEON::BI__builtin_neon_vluti2_laneq_p8:
3926 case NEON::BI__builtin_neon_vluti2_laneq_s16:
3927 case NEON::BI__builtin_neon_vluti2_laneq_s8:
3928 case NEON::BI__builtin_neon_vluti2_laneq_u16:
3929 case NEON::BI__builtin_neon_vluti2_laneq_u8:
3930 case NEON::BI__builtin_neon_vluti2q_laneq_mf8:
3931 case NEON::BI__builtin_neon_vluti2q_laneq_bf16:
3932 case NEON::BI__builtin_neon_vluti2q_laneq_f16:
3933 case NEON::BI__builtin_neon_vluti2q_laneq_p16:
3934 case NEON::BI__builtin_neon_vluti2q_laneq_p8:
3935 case NEON::BI__builtin_neon_vluti2q_laneq_s16:
3936 case NEON::BI__builtin_neon_vluti2q_laneq_s8:
3937 case NEON::BI__builtin_neon_vluti2q_laneq_u16:
3938 case NEON::BI__builtin_neon_vluti2q_laneq_u8:
3939 case NEON::BI__builtin_neon_vluti2_lane_mf8:
3940 case NEON::BI__builtin_neon_vluti2_lane_bf16:
3941 case NEON::BI__builtin_neon_vluti2_lane_f16:
3942 case NEON::BI__builtin_neon_vluti2_lane_p16:
3943 case NEON::BI__builtin_neon_vluti2_lane_p8:
3944 case NEON::BI__builtin_neon_vluti2_lane_s16:
3945 case NEON::BI__builtin_neon_vluti2_lane_s8:
3946 case NEON::BI__builtin_neon_vluti2_lane_u16:
3947 case NEON::BI__builtin_neon_vluti2_lane_u8:
3948 case NEON::BI__builtin_neon_vluti2q_lane_mf8:
3949 case NEON::BI__builtin_neon_vluti2q_lane_bf16:
3950 case NEON::BI__builtin_neon_vluti2q_lane_f16:
3951 case NEON::BI__builtin_neon_vluti2q_lane_p16:
3952 case NEON::BI__builtin_neon_vluti2q_lane_p8:
3953 case NEON::BI__builtin_neon_vluti2q_lane_s16:
3954 case NEON::BI__builtin_neon_vluti2q_lane_s8:
3955 case NEON::BI__builtin_neon_vluti2q_lane_u16:
3956 case NEON::BI__builtin_neon_vluti2q_lane_u8:
3957 case NEON::BI__builtin_neon_vluti4q_lane_mf8:
3958 case NEON::BI__builtin_neon_vluti4q_lane_p8:
3959 case NEON::BI__builtin_neon_vluti4q_lane_s8:
3960 case NEON::BI__builtin_neon_vluti4q_lane_u8:
3961 case NEON::BI__builtin_neon_vluti4q_laneq_mf8:
3962 case NEON::BI__builtin_neon_vluti4q_laneq_p8:
3963 case NEON::BI__builtin_neon_vluti4q_laneq_s8:
3964 case NEON::BI__builtin_neon_vluti4q_laneq_u8:
3965 case NEON::BI__builtin_neon_vluti4q_lane_bf16_x2:
3966 case NEON::BI__builtin_neon_vluti4q_lane_f16_x2:
3967 case NEON::BI__builtin_neon_vluti4q_lane_p16_x2:
3968 case NEON::BI__builtin_neon_vluti4q_lane_s16_x2:
3969 case NEON::BI__builtin_neon_vluti4q_lane_u16_x2:
3970 case NEON::BI__builtin_neon_vluti4q_laneq_bf16_x2:
3971 case NEON::BI__builtin_neon_vluti4q_laneq_f16_x2:
3972 case NEON::BI__builtin_neon_vluti4q_laneq_p16_x2:
3973 case NEON::BI__builtin_neon_vluti4q_laneq_s16_x2:
3974 case NEON::BI__builtin_neon_vluti4q_laneq_u16_x2:
3975 case NEON::BI__builtin_neon_vmmlaq_f16_mf8_fpm:
3976 case NEON::BI__builtin_neon_vmmlaq_f32_mf8_fpm:
3977 case NEON::BI__builtin_neon_vcvt1_low_bf16_mf8_fpm:
3978 case NEON::BI__builtin_neon_vcvt1_bf16_mf8_fpm:
3979 case NEON::BI__builtin_neon_vcvt1_high_bf16_mf8_fpm:
3980 case NEON::BI__builtin_neon_vcvt2_low_bf16_mf8_fpm:
3981 case NEON::BI__builtin_neon_vcvt2_bf16_mf8_fpm:
3982 case NEON::BI__builtin_neon_vcvt2_high_bf16_mf8_fpm:
3983 case NEON::BI__builtin_neon_vcvt1_low_f16_mf8_fpm:
3984 case NEON::BI__builtin_neon_vcvt1_f16_mf8_fpm:
3985 case NEON::BI__builtin_neon_vcvt1_high_f16_mf8_fpm:
3986 case NEON::BI__builtin_neon_vcvt2_low_f16_mf8_fpm:
3987 case NEON::BI__builtin_neon_vcvt2_f16_mf8_fpm:
3988 case NEON::BI__builtin_neon_vcvt2_high_f16_mf8_fpm:
3989 case NEON::BI__builtin_neon_vcvt_mf8_f32_fpm:
3990 case NEON::BI__builtin_neon_vcvt_mf8_f16_fpm:
3991 case NEON::BI__builtin_neon_vcvtq_mf8_f16_fpm:
3992 case NEON::BI__builtin_neon_vcvt_high_mf8_f32_fpm:
3993 case NEON::BI__builtin_neon_vdot_f16_mf8_fpm:
3994 case NEON::BI__builtin_neon_vdotq_f16_mf8_fpm:
3995 case NEON::BI__builtin_neon_vdot_lane_f16_mf8_fpm:
3996 case NEON::BI__builtin_neon_vdotq_lane_f16_mf8_fpm:
3997 case NEON::BI__builtin_neon_vdot_laneq_f16_mf8_fpm:
3998 case NEON::BI__builtin_neon_vdotq_laneq_f16_mf8_fpm:
3999 case NEON::BI__builtin_neon_vdot_f32_mf8_fpm:
4000 case NEON::BI__builtin_neon_vdotq_f32_mf8_fpm:
4001 case NEON::BI__builtin_neon_vdot_lane_f32_mf8_fpm:
4002 case NEON::BI__builtin_neon_vdotq_lane_f32_mf8_fpm:
4003 case NEON::BI__builtin_neon_vdot_laneq_f32_mf8_fpm:
4004 case NEON::BI__builtin_neon_vdotq_laneq_f32_mf8_fpm:
4005 case NEON::BI__builtin_neon_vmlalbq_f16_mf8_fpm:
4006 case NEON::BI__builtin_neon_vmlaltq_f16_mf8_fpm:
4007 case NEON::BI__builtin_neon_vmlallbbq_f32_mf8_fpm:
4008 case NEON::BI__builtin_neon_vmlallbtq_f32_mf8_fpm:
4009 case NEON::BI__builtin_neon_vmlalltbq_f32_mf8_fpm:
4010 case NEON::BI__builtin_neon_vmlallttq_f32_mf8_fpm:
4011 case NEON::BI__builtin_neon_vmlalbq_lane_f16_mf8_fpm:
4012 case NEON::BI__builtin_neon_vmlalbq_laneq_f16_mf8_fpm:
4013 case NEON::BI__builtin_neon_vmlaltq_lane_f16_mf8_fpm:
4014 case NEON::BI__builtin_neon_vmlaltq_laneq_f16_mf8_fpm:
4015 case NEON::BI__builtin_neon_vmlallbbq_lane_f32_mf8_fpm:
4016 case NEON::BI__builtin_neon_vmlallbbq_laneq_f32_mf8_fpm:
4017 case NEON::BI__builtin_neon_vmlallbtq_lane_f32_mf8_fpm:
4018 case NEON::BI__builtin_neon_vmlallbtq_laneq_f32_mf8_fpm:
4019 case NEON::BI__builtin_neon_vmlalltbq_lane_f32_mf8_fpm:
4020 case NEON::BI__builtin_neon_vmlalltbq_laneq_f32_mf8_fpm:
4021 case NEON::BI__builtin_neon_vmlallttq_lane_f32_mf8_fpm:
4022 case NEON::BI__builtin_neon_vmlallttq_laneq_f32_mf8_fpm:
4023 case NEON::BI__builtin_neon_vamin_f16:
4024 case NEON::BI__builtin_neon_vaminq_f16:
4025 case NEON::BI__builtin_neon_vamin_f32:
4026 case NEON::BI__builtin_neon_vaminq_f32:
4027 case NEON::BI__builtin_neon_vaminq_f64:
4028 case NEON::BI__builtin_neon_vamax_f16:
4029 case NEON::BI__builtin_neon_vamaxq_f16:
4030 case NEON::BI__builtin_neon_vamax_f32:
4031 case NEON::BI__builtin_neon_vamaxq_f32:
4032 case NEON::BI__builtin_neon_vamaxq_f64:
4033 case NEON::BI__builtin_neon_vscale_f16:
4034 case NEON::BI__builtin_neon_vscaleq_f16:
4035 case NEON::BI__builtin_neon_vscale_f32:
4036 case NEON::BI__builtin_neon_vscaleq_f32:
4037 case NEON::BI__builtin_neon_vscaleq_f64:
4038 cgm.errorNYI(expr->getSourceRange(),
4039 std::string("unimplemented AArch64 builtin call: ") +
4040 getContext().BuiltinInfo.getName(builtinID));
4041 return mlir::Value{};
4042 }
4043
4044 // Unreachable: All cases in the switch above return.
4045}
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:150
static llvm::SmallVector< RecordMemberKind > getAllDataKinds(llvm::ArrayRef< mlir::Type > members)
One Data kind per member.
Definition CIRTypes.cpp:151
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:854
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:262
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:3012
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:114
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:87
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 uint32_t uint32_t __builtin_riscv_mhacc_i32 __builtin_riscv_mhaccu_u32 __builtin_riscv_mhaccsu_i32 __builtin_riscv_mulq_i32 int64_t
__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.