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