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