1//===---------- ARM.cpp - Emit LLVM Code for builtins ---------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This contains code to emit Builtin calls as LLVM code.
10//
11//===----------------------------------------------------------------------===//
12
13#include "ABIInfo.h"
14#include "CGBuiltin.h"
15#include "CGDebugInfo.h"
16#include "TargetInfo.h"
17#include "clang/Basic/AArch64CodeGenUtils.h"
18#include "clang/Basic/TargetBuiltins.h"
19#include "llvm/IR/InlineAsm.h"
20#include "llvm/IR/IntrinsicsAArch64.h"
21#include "llvm/IR/IntrinsicsARM.h"
22#include "llvm/IR/IntrinsicsBPF.h"
23#include "llvm/TargetParser/AArch64TargetParser.h"
24
25#include <numeric>
26
27using namespace clang;
28using namespace CodeGen;
29using namespace llvm;
30using namespace clang::aarch64;
31
32static std::optional<CodeGenFunction::MSVCIntrin>
33translateAarch64ToMsvcIntrin(unsigned BuiltinID) {
34 using MSVCIntrin = CodeGenFunction::MSVCIntrin;
35 switch (BuiltinID) {
36 default:
37 return std::nullopt;
38 case clang::AArch64::BI_BitScanForward:
39 case clang::AArch64::BI_BitScanForward64:
40 return MSVCIntrin::_BitScanForward;
41 case clang::AArch64::BI_BitScanReverse:
42 case clang::AArch64::BI_BitScanReverse64:
43 return MSVCIntrin::_BitScanReverse;
44 case clang::AArch64::BI_InterlockedAnd64:
45 return MSVCIntrin::_InterlockedAnd;
46 case clang::AArch64::BI_InterlockedExchange64:
47 return MSVCIntrin::_InterlockedExchange;
48 case clang::AArch64::BI_InterlockedExchangeAdd64:
49 return MSVCIntrin::_InterlockedExchangeAdd;
50 case clang::AArch64::BI_InterlockedExchangeSub64:
51 return MSVCIntrin::_InterlockedExchangeSub;
52 case clang::AArch64::BI_InterlockedOr64:
53 return MSVCIntrin::_InterlockedOr;
54 case clang::AArch64::BI_InterlockedXor64:
55 return MSVCIntrin::_InterlockedXor;
56 case clang::AArch64::BI_InterlockedDecrement64:
57 return MSVCIntrin::_InterlockedDecrement;
58 case clang::AArch64::BI_InterlockedIncrement64:
59 return MSVCIntrin::_InterlockedIncrement;
60 case clang::AArch64::BI_InterlockedExchangeAdd8_acq:
61 case clang::AArch64::BI_InterlockedExchangeAdd16_acq:
62 case clang::AArch64::BI_InterlockedExchangeAdd_acq:
63 case clang::AArch64::BI_InterlockedExchangeAdd64_acq:
64 return MSVCIntrin::_InterlockedExchangeAdd_acq;
65 case clang::AArch64::BI_InterlockedExchangeAdd8_rel:
66 case clang::AArch64::BI_InterlockedExchangeAdd16_rel:
67 case clang::AArch64::BI_InterlockedExchangeAdd_rel:
68 case clang::AArch64::BI_InterlockedExchangeAdd64_rel:
69 return MSVCIntrin::_InterlockedExchangeAdd_rel;
70 case clang::AArch64::BI_InterlockedExchangeAdd8_nf:
71 case clang::AArch64::BI_InterlockedExchangeAdd16_nf:
72 case clang::AArch64::BI_InterlockedExchangeAdd_nf:
73 case clang::AArch64::BI_InterlockedExchangeAdd64_nf:
74 return MSVCIntrin::_InterlockedExchangeAdd_nf;
75 case clang::AArch64::BI_InterlockedExchange8_acq:
76 case clang::AArch64::BI_InterlockedExchange16_acq:
77 case clang::AArch64::BI_InterlockedExchange_acq:
78 case clang::AArch64::BI_InterlockedExchange64_acq:
79 case clang::AArch64::BI_InterlockedExchangePointer_acq:
80 return MSVCIntrin::_InterlockedExchange_acq;
81 case clang::AArch64::BI_InterlockedExchange8_rel:
82 case clang::AArch64::BI_InterlockedExchange16_rel:
83 case clang::AArch64::BI_InterlockedExchange_rel:
84 case clang::AArch64::BI_InterlockedExchange64_rel:
85 case clang::AArch64::BI_InterlockedExchangePointer_rel:
86 return MSVCIntrin::_InterlockedExchange_rel;
87 case clang::AArch64::BI_InterlockedExchange8_nf:
88 case clang::AArch64::BI_InterlockedExchange16_nf:
89 case clang::AArch64::BI_InterlockedExchange_nf:
90 case clang::AArch64::BI_InterlockedExchange64_nf:
91 case clang::AArch64::BI_InterlockedExchangePointer_nf:
92 return MSVCIntrin::_InterlockedExchange_nf;
93 case clang::AArch64::BI_InterlockedCompareExchange8_acq:
94 case clang::AArch64::BI_InterlockedCompareExchange16_acq:
95 case clang::AArch64::BI_InterlockedCompareExchange_acq:
96 case clang::AArch64::BI_InterlockedCompareExchange64_acq:
97 case clang::AArch64::BI_InterlockedCompareExchangePointer_acq:
98 return MSVCIntrin::_InterlockedCompareExchange_acq;
99 case clang::AArch64::BI_InterlockedCompareExchange8_rel:
100 case clang::AArch64::BI_InterlockedCompareExchange16_rel:
101 case clang::AArch64::BI_InterlockedCompareExchange_rel:
102 case clang::AArch64::BI_InterlockedCompareExchange64_rel:
103 case clang::AArch64::BI_InterlockedCompareExchangePointer_rel:
104 return MSVCIntrin::_InterlockedCompareExchange_rel;
105 case clang::AArch64::BI_InterlockedCompareExchange8_nf:
106 case clang::AArch64::BI_InterlockedCompareExchange16_nf:
107 case clang::AArch64::BI_InterlockedCompareExchange_nf:
108 case clang::AArch64::BI_InterlockedCompareExchange64_nf:
109 return MSVCIntrin::_InterlockedCompareExchange_nf;
110 case clang::AArch64::BI_InterlockedCompareExchange128:
111 return MSVCIntrin::_InterlockedCompareExchange128;
112 case clang::AArch64::BI_InterlockedCompareExchange128_acq:
113 return MSVCIntrin::_InterlockedCompareExchange128_acq;
114 case clang::AArch64::BI_InterlockedCompareExchange128_nf:
115 return MSVCIntrin::_InterlockedCompareExchange128_nf;
116 case clang::AArch64::BI_InterlockedCompareExchange128_rel:
117 return MSVCIntrin::_InterlockedCompareExchange128_rel;
118 case clang::AArch64::BI_InterlockedOr8_acq:
119 case clang::AArch64::BI_InterlockedOr16_acq:
120 case clang::AArch64::BI_InterlockedOr_acq:
121 case clang::AArch64::BI_InterlockedOr64_acq:
122 return MSVCIntrin::_InterlockedOr_acq;
123 case clang::AArch64::BI_InterlockedOr8_rel:
124 case clang::AArch64::BI_InterlockedOr16_rel:
125 case clang::AArch64::BI_InterlockedOr_rel:
126 case clang::AArch64::BI_InterlockedOr64_rel:
127 return MSVCIntrin::_InterlockedOr_rel;
128 case clang::AArch64::BI_InterlockedOr8_nf:
129 case clang::AArch64::BI_InterlockedOr16_nf:
130 case clang::AArch64::BI_InterlockedOr_nf:
131 case clang::AArch64::BI_InterlockedOr64_nf:
132 return MSVCIntrin::_InterlockedOr_nf;
133 case clang::AArch64::BI_InterlockedXor8_acq:
134 case clang::AArch64::BI_InterlockedXor16_acq:
135 case clang::AArch64::BI_InterlockedXor_acq:
136 case clang::AArch64::BI_InterlockedXor64_acq:
137 return MSVCIntrin::_InterlockedXor_acq;
138 case clang::AArch64::BI_InterlockedXor8_rel:
139 case clang::AArch64::BI_InterlockedXor16_rel:
140 case clang::AArch64::BI_InterlockedXor_rel:
141 case clang::AArch64::BI_InterlockedXor64_rel:
142 return MSVCIntrin::_InterlockedXor_rel;
143 case clang::AArch64::BI_InterlockedXor8_nf:
144 case clang::AArch64::BI_InterlockedXor16_nf:
145 case clang::AArch64::BI_InterlockedXor_nf:
146 case clang::AArch64::BI_InterlockedXor64_nf:
147 return MSVCIntrin::_InterlockedXor_nf;
148 case clang::AArch64::BI_InterlockedAnd8_acq:
149 case clang::AArch64::BI_InterlockedAnd16_acq:
150 case clang::AArch64::BI_InterlockedAnd_acq:
151 case clang::AArch64::BI_InterlockedAnd64_acq:
152 return MSVCIntrin::_InterlockedAnd_acq;
153 case clang::AArch64::BI_InterlockedAnd8_rel:
154 case clang::AArch64::BI_InterlockedAnd16_rel:
155 case clang::AArch64::BI_InterlockedAnd_rel:
156 case clang::AArch64::BI_InterlockedAnd64_rel:
157 return MSVCIntrin::_InterlockedAnd_rel;
158 case clang::AArch64::BI_InterlockedAnd8_nf:
159 case clang::AArch64::BI_InterlockedAnd16_nf:
160 case clang::AArch64::BI_InterlockedAnd_nf:
161 case clang::AArch64::BI_InterlockedAnd64_nf:
162 return MSVCIntrin::_InterlockedAnd_nf;
163 case clang::AArch64::BI_InterlockedIncrement16_acq:
164 case clang::AArch64::BI_InterlockedIncrement_acq:
165 case clang::AArch64::BI_InterlockedIncrement64_acq:
166 return MSVCIntrin::_InterlockedIncrement_acq;
167 case clang::AArch64::BI_InterlockedIncrement16_rel:
168 case clang::AArch64::BI_InterlockedIncrement_rel:
169 case clang::AArch64::BI_InterlockedIncrement64_rel:
170 return MSVCIntrin::_InterlockedIncrement_rel;
171 case clang::AArch64::BI_InterlockedIncrement16_nf:
172 case clang::AArch64::BI_InterlockedIncrement_nf:
173 case clang::AArch64::BI_InterlockedIncrement64_nf:
174 return MSVCIntrin::_InterlockedIncrement_nf;
175 case clang::AArch64::BI_InterlockedDecrement16_acq:
176 case clang::AArch64::BI_InterlockedDecrement_acq:
177 case clang::AArch64::BI_InterlockedDecrement64_acq:
178 return MSVCIntrin::_InterlockedDecrement_acq;
179 case clang::AArch64::BI_InterlockedDecrement16_rel:
180 case clang::AArch64::BI_InterlockedDecrement_rel:
181 case clang::AArch64::BI_InterlockedDecrement64_rel:
182 return MSVCIntrin::_InterlockedDecrement_rel;
183 case clang::AArch64::BI_InterlockedDecrement16_nf:
184 case clang::AArch64::BI_InterlockedDecrement_nf:
185 case clang::AArch64::BI_InterlockedDecrement64_nf:
186 return MSVCIntrin::_InterlockedDecrement_nf;
187 }
188 llvm_unreachable("must return from switch");
189}
190
191static std::optional<CodeGenFunction::MSVCIntrin>
192translateArmToMsvcIntrin(unsigned BuiltinID) {
193 using MSVCIntrin = CodeGenFunction::MSVCIntrin;
194 switch (BuiltinID) {
195 default:
196 return std::nullopt;
197 case clang::ARM::BI_BitScanForward:
198 case clang::ARM::BI_BitScanForward64:
199 return MSVCIntrin::_BitScanForward;
200 case clang::ARM::BI_BitScanReverse:
201 case clang::ARM::BI_BitScanReverse64:
202 return MSVCIntrin::_BitScanReverse;
203 case clang::ARM::BI_InterlockedAnd64:
204 return MSVCIntrin::_InterlockedAnd;
205 case clang::ARM::BI_InterlockedExchange64:
206 return MSVCIntrin::_InterlockedExchange;
207 case clang::ARM::BI_InterlockedExchangeAdd64:
208 return MSVCIntrin::_InterlockedExchangeAdd;
209 case clang::ARM::BI_InterlockedExchangeSub64:
210 return MSVCIntrin::_InterlockedExchangeSub;
211 case clang::ARM::BI_InterlockedOr64:
212 return MSVCIntrin::_InterlockedOr;
213 case clang::ARM::BI_InterlockedXor64:
214 return MSVCIntrin::_InterlockedXor;
215 case clang::ARM::BI_InterlockedDecrement64:
216 return MSVCIntrin::_InterlockedDecrement;
217 case clang::ARM::BI_InterlockedIncrement64:
218 return MSVCIntrin::_InterlockedIncrement;
219 case clang::ARM::BI_InterlockedExchangeAdd8_acq:
220 case clang::ARM::BI_InterlockedExchangeAdd16_acq:
221 case clang::ARM::BI_InterlockedExchangeAdd_acq:
222 case clang::ARM::BI_InterlockedExchangeAdd64_acq:
223 return MSVCIntrin::_InterlockedExchangeAdd_acq;
224 case clang::ARM::BI_InterlockedExchangeAdd8_rel:
225 case clang::ARM::BI_InterlockedExchangeAdd16_rel:
226 case clang::ARM::BI_InterlockedExchangeAdd_rel:
227 case clang::ARM::BI_InterlockedExchangeAdd64_rel:
228 return MSVCIntrin::_InterlockedExchangeAdd_rel;
229 case clang::ARM::BI_InterlockedExchangeAdd8_nf:
230 case clang::ARM::BI_InterlockedExchangeAdd16_nf:
231 case clang::ARM::BI_InterlockedExchangeAdd_nf:
232 case clang::ARM::BI_InterlockedExchangeAdd64_nf:
233 return MSVCIntrin::_InterlockedExchangeAdd_nf;
234 case clang::ARM::BI_InterlockedExchange8_acq:
235 case clang::ARM::BI_InterlockedExchange16_acq:
236 case clang::ARM::BI_InterlockedExchange_acq:
237 case clang::ARM::BI_InterlockedExchange64_acq:
238 case clang::ARM::BI_InterlockedExchangePointer_acq:
239 return MSVCIntrin::_InterlockedExchange_acq;
240 case clang::ARM::BI_InterlockedExchange8_rel:
241 case clang::ARM::BI_InterlockedExchange16_rel:
242 case clang::ARM::BI_InterlockedExchange_rel:
243 case clang::ARM::BI_InterlockedExchange64_rel:
244 case clang::ARM::BI_InterlockedExchangePointer_rel:
245 return MSVCIntrin::_InterlockedExchange_rel;
246 case clang::ARM::BI_InterlockedExchange8_nf:
247 case clang::ARM::BI_InterlockedExchange16_nf:
248 case clang::ARM::BI_InterlockedExchange_nf:
249 case clang::ARM::BI_InterlockedExchange64_nf:
250 case clang::ARM::BI_InterlockedExchangePointer_nf:
251 return MSVCIntrin::_InterlockedExchange_nf;
252 case clang::ARM::BI_InterlockedCompareExchange8_acq:
253 case clang::ARM::BI_InterlockedCompareExchange16_acq:
254 case clang::ARM::BI_InterlockedCompareExchange_acq:
255 case clang::ARM::BI_InterlockedCompareExchange64_acq:
256 case clang::ARM::BI_InterlockedCompareExchangePointer_acq:
257 return MSVCIntrin::_InterlockedCompareExchange_acq;
258 case clang::ARM::BI_InterlockedCompareExchange8_rel:
259 case clang::ARM::BI_InterlockedCompareExchange16_rel:
260 case clang::ARM::BI_InterlockedCompareExchange_rel:
261 case clang::ARM::BI_InterlockedCompareExchange64_rel:
262 case clang::ARM::BI_InterlockedCompareExchangePointer_rel:
263 return MSVCIntrin::_InterlockedCompareExchange_rel;
264 case clang::ARM::BI_InterlockedCompareExchange8_nf:
265 case clang::ARM::BI_InterlockedCompareExchange16_nf:
266 case clang::ARM::BI_InterlockedCompareExchange_nf:
267 case clang::ARM::BI_InterlockedCompareExchange64_nf:
268 return MSVCIntrin::_InterlockedCompareExchange_nf;
269 case clang::ARM::BI_InterlockedOr8_acq:
270 case clang::ARM::BI_InterlockedOr16_acq:
271 case clang::ARM::BI_InterlockedOr_acq:
272 case clang::ARM::BI_InterlockedOr64_acq:
273 return MSVCIntrin::_InterlockedOr_acq;
274 case clang::ARM::BI_InterlockedOr8_rel:
275 case clang::ARM::BI_InterlockedOr16_rel:
276 case clang::ARM::BI_InterlockedOr_rel:
277 case clang::ARM::BI_InterlockedOr64_rel:
278 return MSVCIntrin::_InterlockedOr_rel;
279 case clang::ARM::BI_InterlockedOr8_nf:
280 case clang::ARM::BI_InterlockedOr16_nf:
281 case clang::ARM::BI_InterlockedOr_nf:
282 case clang::ARM::BI_InterlockedOr64_nf:
283 return MSVCIntrin::_InterlockedOr_nf;
284 case clang::ARM::BI_InterlockedXor8_acq:
285 case clang::ARM::BI_InterlockedXor16_acq:
286 case clang::ARM::BI_InterlockedXor_acq:
287 case clang::ARM::BI_InterlockedXor64_acq:
288 return MSVCIntrin::_InterlockedXor_acq;
289 case clang::ARM::BI_InterlockedXor8_rel:
290 case clang::ARM::BI_InterlockedXor16_rel:
291 case clang::ARM::BI_InterlockedXor_rel:
292 case clang::ARM::BI_InterlockedXor64_rel:
293 return MSVCIntrin::_InterlockedXor_rel;
294 case clang::ARM::BI_InterlockedXor8_nf:
295 case clang::ARM::BI_InterlockedXor16_nf:
296 case clang::ARM::BI_InterlockedXor_nf:
297 case clang::ARM::BI_InterlockedXor64_nf:
298 return MSVCIntrin::_InterlockedXor_nf;
299 case clang::ARM::BI_InterlockedAnd8_acq:
300 case clang::ARM::BI_InterlockedAnd16_acq:
301 case clang::ARM::BI_InterlockedAnd_acq:
302 case clang::ARM::BI_InterlockedAnd64_acq:
303 return MSVCIntrin::_InterlockedAnd_acq;
304 case clang::ARM::BI_InterlockedAnd8_rel:
305 case clang::ARM::BI_InterlockedAnd16_rel:
306 case clang::ARM::BI_InterlockedAnd_rel:
307 case clang::ARM::BI_InterlockedAnd64_rel:
308 return MSVCIntrin::_InterlockedAnd_rel;
309 case clang::ARM::BI_InterlockedAnd8_nf:
310 case clang::ARM::BI_InterlockedAnd16_nf:
311 case clang::ARM::BI_InterlockedAnd_nf:
312 case clang::ARM::BI_InterlockedAnd64_nf:
313 return MSVCIntrin::_InterlockedAnd_nf;
314 case clang::ARM::BI_InterlockedIncrement16_acq:
315 case clang::ARM::BI_InterlockedIncrement_acq:
316 case clang::ARM::BI_InterlockedIncrement64_acq:
317 return MSVCIntrin::_InterlockedIncrement_acq;
318 case clang::ARM::BI_InterlockedIncrement16_rel:
319 case clang::ARM::BI_InterlockedIncrement_rel:
320 case clang::ARM::BI_InterlockedIncrement64_rel:
321 return MSVCIntrin::_InterlockedIncrement_rel;
322 case clang::ARM::BI_InterlockedIncrement16_nf:
323 case clang::ARM::BI_InterlockedIncrement_nf:
324 case clang::ARM::BI_InterlockedIncrement64_nf:
325 return MSVCIntrin::_InterlockedIncrement_nf;
326 case clang::ARM::BI_InterlockedDecrement16_acq:
327 case clang::ARM::BI_InterlockedDecrement_acq:
328 case clang::ARM::BI_InterlockedDecrement64_acq:
329 return MSVCIntrin::_InterlockedDecrement_acq;
330 case clang::ARM::BI_InterlockedDecrement16_rel:
331 case clang::ARM::BI_InterlockedDecrement_rel:
332 case clang::ARM::BI_InterlockedDecrement64_rel:
333 return MSVCIntrin::_InterlockedDecrement_rel;
334 case clang::ARM::BI_InterlockedDecrement16_nf:
335 case clang::ARM::BI_InterlockedDecrement_nf:
336 case clang::ARM::BI_InterlockedDecrement64_nf:
337 return MSVCIntrin::_InterlockedDecrement_nf;
338 }
339 llvm_unreachable("must return from switch");
340}
341
342// Emit an intrinsic where all operands are of the same type as the result.
343// Depending on mode, this may be a constrained floating-point intrinsic.
344static Value *emitCallMaybeConstrainedFPBuiltin(CodeGenFunction &CGF,
345 unsigned IntrinsicID,
346 unsigned ConstrainedIntrinsicID,
347 llvm::Type *Ty,
348 ArrayRef<Value *> Args) {
349 Function *F;
350 if (CGF.Builder.getIsFPConstrained())
351 F = CGF.CGM.getIntrinsic(IID: ConstrainedIntrinsicID, Tys: Ty);
352 else
353 F = CGF.CGM.getIntrinsic(IID: IntrinsicID, Tys: Ty);
354
355 if (CGF.Builder.getIsFPConstrained())
356 return CGF.Builder.CreateConstrainedFPCall(Callee: F, Args);
357
358 return CGF.Builder.CreateCall(Callee: F, Args);
359}
360
361static llvm::FixedVectorType *GetNeonType(CodeGenFunction *CGF,
362 NeonTypeFlags TypeFlags,
363 bool HasFastHalfType = true,
364 bool V1Ty = false,
365 bool AllowBFloatArgsAndRet = true) {
366 int IsQuad = TypeFlags.isQuad();
367 switch (TypeFlags.getEltType()) {
368 case NeonTypeFlags::Int8:
369 case NeonTypeFlags::Poly8:
370 case NeonTypeFlags::MFloat8:
371 return llvm::FixedVectorType::get(ElementType: CGF->Int8Ty, NumElts: V1Ty ? 1 : (8 << IsQuad));
372 case NeonTypeFlags::Int16:
373 case NeonTypeFlags::Poly16:
374 return llvm::FixedVectorType::get(ElementType: CGF->Int16Ty, NumElts: V1Ty ? 1 : (4 << IsQuad));
375 case NeonTypeFlags::BFloat16:
376 if (AllowBFloatArgsAndRet)
377 return llvm::FixedVectorType::get(ElementType: CGF->BFloatTy, NumElts: V1Ty ? 1 : (4 << IsQuad));
378 return llvm::FixedVectorType::get(ElementType: CGF->Int16Ty, NumElts: V1Ty ? 1 : (4 << IsQuad));
379 case NeonTypeFlags::Float16:
380 if (HasFastHalfType)
381 return llvm::FixedVectorType::get(ElementType: CGF->HalfTy, NumElts: V1Ty ? 1 : (4 << IsQuad));
382 return llvm::FixedVectorType::get(ElementType: CGF->Int16Ty, NumElts: V1Ty ? 1 : (4 << IsQuad));
383 case NeonTypeFlags::Int32:
384 return llvm::FixedVectorType::get(ElementType: CGF->Int32Ty, NumElts: V1Ty ? 1 : (2 << IsQuad));
385 case NeonTypeFlags::Int64:
386 case NeonTypeFlags::Poly64:
387 return llvm::FixedVectorType::get(ElementType: CGF->Int64Ty, NumElts: V1Ty ? 1 : (1 << IsQuad));
388 case NeonTypeFlags::Poly128:
389 // FIXME: i128 and f128 doesn't get fully support in Clang and llvm.
390 // There is a lot of i128 and f128 API missing.
391 // so we use v16i8 to represent poly128 and get pattern matched.
392 return llvm::FixedVectorType::get(ElementType: CGF->Int8Ty, NumElts: 16);
393 case NeonTypeFlags::Float32:
394 return llvm::FixedVectorType::get(ElementType: CGF->FloatTy, NumElts: V1Ty ? 1 : (2 << IsQuad));
395 case NeonTypeFlags::Float64:
396 return llvm::FixedVectorType::get(ElementType: CGF->DoubleTy, NumElts: V1Ty ? 1 : (1 << IsQuad));
397 }
398 llvm_unreachable("Unknown vector element type!");
399}
400
401static llvm::VectorType *GetFloatNeonType(CodeGenFunction *CGF,
402 NeonTypeFlags IntTypeFlags) {
403 int IsQuad = IntTypeFlags.isQuad();
404 switch (IntTypeFlags.getEltType()) {
405 case NeonTypeFlags::Int16:
406 return llvm::FixedVectorType::get(ElementType: CGF->HalfTy, NumElts: (4 << IsQuad));
407 case NeonTypeFlags::Int32:
408 return llvm::FixedVectorType::get(ElementType: CGF->FloatTy, NumElts: (2 << IsQuad));
409 case NeonTypeFlags::Int64:
410 return llvm::FixedVectorType::get(ElementType: CGF->DoubleTy, NumElts: (1 << IsQuad));
411 default:
412 llvm_unreachable("Type can't be converted to floating-point!");
413 }
414}
415
416Value *CodeGenFunction::EmitNeonSplat(Value *V, Constant *C,
417 const ElementCount &Count) {
418 Value *SV = llvm::ConstantVector::getSplat(EC: Count, Elt: C);
419 return Builder.CreateShuffleVector(V1: V, V2: V, Mask: SV, Name: "lane");
420}
421
422Value *CodeGenFunction::EmitNeonSplat(Value *V, Constant *C) {
423 ElementCount EC = cast<llvm::VectorType>(Val: V->getType())->getElementCount();
424 return EmitNeonSplat(V, C, Count: EC);
425}
426
427Value *CodeGenFunction::EmitNeonCall(Function *F, SmallVectorImpl<Value*> &Ops,
428 const char *name,
429 unsigned shift, bool rightshift) {
430 unsigned j = 0;
431 for (Function::const_arg_iterator ai = F->arg_begin(), ae = F->arg_end();
432 ai != ae; ++ai, ++j) {
433 if (F->isConstrainedFPIntrinsic())
434 if (ai->getType()->isMetadataTy())
435 continue;
436 if (shift > 0 && shift == j)
437 Ops[j] = EmitNeonShiftVector(V: Ops[j], Ty: ai->getType(), negateForRightShift: rightshift);
438 else
439 Ops[j] = Builder.CreateBitCast(V: Ops[j], DestTy: ai->getType(), Name: name);
440 }
441
442 if (F->isConstrainedFPIntrinsic())
443 return Builder.CreateConstrainedFPCall(Callee: F, Args: Ops, Name: name);
444 return Builder.CreateCall(Callee: F, Args: Ops, Name: name);
445}
446
447Value *CodeGenFunction::EmitFP8NeonCall(unsigned IID,
448 ArrayRef<llvm::Type *> Tys,
449 SmallVectorImpl<Value *> &Ops,
450 const CallExpr *E, const char *name) {
451 Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_set_fpmr),
452 Args: Ops.pop_back_val());
453 return EmitNeonCall(F: CGM.getIntrinsic(IID, Tys), Ops, name);
454}
455
456llvm::Value *CodeGenFunction::EmitFP8NeonFDOTCall(
457 unsigned IID, bool ExtendLaneArg, llvm::Type *RetTy,
458 SmallVectorImpl<llvm::Value *> &Ops, const CallExpr *E, const char *name) {
459
460 const unsigned ElemCount = Ops[0]->getType()->getPrimitiveSizeInBits() /
461 RetTy->getPrimitiveSizeInBits();
462 llvm::Type *Tys[] = {llvm::FixedVectorType::get(ElementType: RetTy, NumElts: ElemCount),
463 Ops[1]->getType()};
464 if (ExtendLaneArg) {
465 auto *VT = llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: 16);
466 Ops[2] = Builder.CreateInsertVector(DstType: VT, SrcVec: PoisonValue::get(T: VT), SubVec: Ops[2],
467 Idx: uint64_t(0));
468 }
469 return EmitFP8NeonCall(IID, Tys, Ops, E, name);
470}
471
472llvm::Value *CodeGenFunction::EmitFP8NeonFMLACall(
473 unsigned IID, bool ExtendLaneArg, llvm::Type *RetTy,
474 SmallVectorImpl<llvm::Value *> &Ops, const CallExpr *E, const char *name) {
475
476 if (ExtendLaneArg) {
477 auto *VT = llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: 16);
478 Ops[2] = Builder.CreateInsertVector(DstType: VT, SrcVec: PoisonValue::get(T: VT), SubVec: Ops[2],
479 Idx: uint64_t(0));
480 }
481 const unsigned ElemCount = Ops[0]->getType()->getPrimitiveSizeInBits() /
482 RetTy->getPrimitiveSizeInBits();
483 return EmitFP8NeonCall(IID, Tys: {llvm::FixedVectorType::get(ElementType: RetTy, NumElts: ElemCount)},
484 Ops, E, name);
485}
486
487Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty,
488 bool neg) {
489 int SV = cast<ConstantInt>(Val: V)->getSExtValue();
490 return ConstantInt::getSigned(Ty, V: neg ? -SV : SV);
491}
492
493Value *CodeGenFunction::EmitFP8NeonCvtCall(unsigned IID, llvm::Type *Ty0,
494 llvm::Type *Ty1, bool Extract,
495 SmallVectorImpl<llvm::Value *> &Ops,
496 const CallExpr *E,
497 const char *name) {
498 llvm::Type *Tys[] = {Ty0, Ty1};
499 if (Extract) {
500 // Op[0] is mfloat8x16_t, but the intrinsic converts only the lower part of
501 // the vector.
502 Tys[1] = llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: 8);
503 Ops[0] = Builder.CreateExtractVector(DstType: Tys[1], SrcVec: Ops[0], Idx: uint64_t(0));
504 }
505 return EmitFP8NeonCall(IID, Tys, Ops, E, name);
506}
507
508// Right-shift a vector by a constant.
509Value *CodeGenFunction::EmitNeonRShiftImm(Value *Vec, Value *Shift,
510 llvm::Type *Ty, bool usgn,
511 const char *name) {
512 llvm::VectorType *VTy = cast<llvm::VectorType>(Val: Ty);
513
514 int ShiftAmt = cast<ConstantInt>(Val: Shift)->getSExtValue();
515 int EltSize = VTy->getScalarSizeInBits();
516
517 Vec = Builder.CreateBitCast(V: Vec, DestTy: Ty);
518
519 // lshr/ashr are undefined when the shift amount is equal to the vector
520 // element size.
521 if (ShiftAmt == EltSize) {
522 if (usgn) {
523 // Right-shifting an unsigned value by its size yields 0.
524 return llvm::ConstantAggregateZero::get(Ty: VTy);
525 } else {
526 // Right-shifting a signed value by its size is equivalent
527 // to a shift of size-1.
528 --ShiftAmt;
529 Shift = ConstantInt::get(Ty: VTy->getElementType(), V: ShiftAmt);
530 }
531 }
532
533 Shift = EmitNeonShiftVector(V: Shift, Ty, neg: false);
534 if (usgn)
535 return Builder.CreateLShr(LHS: Vec, RHS: Shift, Name: name);
536 return Builder.CreateAShr(LHS: Vec, RHS: Shift, Name: name);
537}
538
539// clang-format off
540static const ARMNeonVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
541 NEONMAP1(__a32_vcvt_bf16_f32, arm_neon_vcvtfp2bf, 0),
542 NEONMAP0(splat_lane_v),
543 NEONMAP0(splat_laneq_v),
544 NEONMAP0(splatq_lane_v),
545 NEONMAP0(splatq_laneq_v),
546 NEONMAP2(vabd_v, arm_neon_vabdu, arm_neon_vabds, Add1ArgType | UnsignedAlts),
547 NEONMAP2(vabdq_v, arm_neon_vabdu, arm_neon_vabds, Add1ArgType | UnsignedAlts),
548 NEONMAP1(vabs_v, arm_neon_vabs, 0),
549 NEONMAP1(vabsq_v, arm_neon_vabs, 0),
550 NEONMAP0(vadd_v),
551 NEONMAP0(vaddhn_v),
552 NEONMAP0(vaddq_v),
553 NEONMAP1(vaesdq_u8, arm_neon_aesd, 0),
554 NEONMAP1(vaeseq_u8, arm_neon_aese, 0),
555 NEONMAP1(vaesimcq_u8, arm_neon_aesimc, 0),
556 NEONMAP1(vaesmcq_u8, arm_neon_aesmc, 0),
557 NEONMAP1(vbfdot_f32, arm_neon_bfdot, 0),
558 NEONMAP1(vbfdotq_f32, arm_neon_bfdot, 0),
559 NEONMAP1(vbfmlalbq_f32, arm_neon_bfmlalb, 0),
560 NEONMAP1(vbfmlaltq_f32, arm_neon_bfmlalt, 0),
561 NEONMAP1(vbfmmlaq_f32, arm_neon_bfmmla, 0),
562 NEONMAP1(vbsl_v, arm_neon_vbsl, AddRetType),
563 NEONMAP1(vbslq_v, arm_neon_vbsl, AddRetType),
564 NEONMAP1(vcadd_rot270_f16, arm_neon_vcadd_rot270, Add1ArgType),
565 NEONMAP1(vcadd_rot270_f32, arm_neon_vcadd_rot270, Add1ArgType),
566 NEONMAP1(vcadd_rot90_f16, arm_neon_vcadd_rot90, Add1ArgType),
567 NEONMAP1(vcadd_rot90_f32, arm_neon_vcadd_rot90, Add1ArgType),
568 NEONMAP1(vcaddq_rot270_f16, arm_neon_vcadd_rot270, Add1ArgType),
569 NEONMAP1(vcaddq_rot270_f32, arm_neon_vcadd_rot270, Add1ArgType),
570 NEONMAP1(vcaddq_rot270_f64, arm_neon_vcadd_rot270, Add1ArgType),
571 NEONMAP1(vcaddq_rot90_f16, arm_neon_vcadd_rot90, Add1ArgType),
572 NEONMAP1(vcaddq_rot90_f32, arm_neon_vcadd_rot90, Add1ArgType),
573 NEONMAP1(vcaddq_rot90_f64, arm_neon_vcadd_rot90, Add1ArgType),
574 NEONMAP1(vcage_v, arm_neon_vacge, 0),
575 NEONMAP1(vcageq_v, arm_neon_vacge, 0),
576 NEONMAP1(vcagt_v, arm_neon_vacgt, 0),
577 NEONMAP1(vcagtq_v, arm_neon_vacgt, 0),
578 NEONMAP1(vcale_v, arm_neon_vacge, 0),
579 NEONMAP1(vcaleq_v, arm_neon_vacge, 0),
580 NEONMAP1(vcalt_v, arm_neon_vacgt, 0),
581 NEONMAP1(vcaltq_v, arm_neon_vacgt, 0),
582 NEONMAP0(vceqz_v),
583 NEONMAP0(vceqzq_v),
584 NEONMAP0(vcgez_v),
585 NEONMAP0(vcgezq_v),
586 NEONMAP0(vcgtz_v),
587 NEONMAP0(vcgtzq_v),
588 NEONMAP0(vclez_v),
589 NEONMAP0(vclezq_v),
590 NEONMAP1(vcls_v, arm_neon_vcls, Add1ArgType),
591 NEONMAP1(vclsq_v, arm_neon_vcls, Add1ArgType),
592 NEONMAP0(vcltz_v),
593 NEONMAP0(vcltzq_v),
594 NEONMAP1(vclz_v, ctlz, Add1ArgType),
595 NEONMAP1(vclzq_v, ctlz, Add1ArgType),
596 NEONMAP1(vcnt_v, ctpop, Add1ArgType),
597 NEONMAP1(vcntq_v, ctpop, Add1ArgType),
598 NEONMAP0(vcvt_f16_s16),
599 NEONMAP0(vcvt_f16_u16),
600 NEONMAP0(vcvt_f32_v),
601 NEONMAP1(vcvt_n_f16_s16, arm_neon_vcvtfxs2fp, 0),
602 NEONMAP1(vcvt_n_f16_u16, arm_neon_vcvtfxu2fp, 0),
603 NEONMAP2(vcvt_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
604 NEONMAP1(vcvt_n_s16_f16, arm_neon_vcvtfp2fxs, 0),
605 NEONMAP1(vcvt_n_s32_v, arm_neon_vcvtfp2fxs, 0),
606 NEONMAP1(vcvt_n_s64_v, arm_neon_vcvtfp2fxs, 0),
607 NEONMAP1(vcvt_n_u16_f16, arm_neon_vcvtfp2fxu, 0),
608 NEONMAP1(vcvt_n_u32_v, arm_neon_vcvtfp2fxu, 0),
609 NEONMAP1(vcvt_n_u64_v, arm_neon_vcvtfp2fxu, 0),
610 NEONMAP0(vcvt_s16_f16),
611 NEONMAP0(vcvt_s32_v),
612 NEONMAP0(vcvt_s64_v),
613 NEONMAP0(vcvt_u16_f16),
614 NEONMAP0(vcvt_u32_v),
615 NEONMAP0(vcvt_u64_v),
616 NEONMAP1(vcvta_s16_f16, arm_neon_vcvtas, 0),
617 NEONMAP1(vcvta_s32_v, arm_neon_vcvtas, 0),
618 NEONMAP1(vcvta_s64_v, arm_neon_vcvtas, 0),
619 NEONMAP1(vcvta_u16_f16, arm_neon_vcvtau, 0),
620 NEONMAP1(vcvta_u32_v, arm_neon_vcvtau, 0),
621 NEONMAP1(vcvta_u64_v, arm_neon_vcvtau, 0),
622 NEONMAP1(vcvtaq_s16_f16, arm_neon_vcvtas, 0),
623 NEONMAP1(vcvtaq_s32_v, arm_neon_vcvtas, 0),
624 NEONMAP1(vcvtaq_s64_v, arm_neon_vcvtas, 0),
625 NEONMAP1(vcvtaq_u16_f16, arm_neon_vcvtau, 0),
626 NEONMAP1(vcvtaq_u32_v, arm_neon_vcvtau, 0),
627 NEONMAP1(vcvtaq_u64_v, arm_neon_vcvtau, 0),
628 NEONMAP1(vcvth_bf16_f32, arm_neon_vcvtbfp2bf, 0),
629 NEONMAP1(vcvtm_s16_f16, arm_neon_vcvtms, 0),
630 NEONMAP1(vcvtm_s32_v, arm_neon_vcvtms, 0),
631 NEONMAP1(vcvtm_s64_v, arm_neon_vcvtms, 0),
632 NEONMAP1(vcvtm_u16_f16, arm_neon_vcvtmu, 0),
633 NEONMAP1(vcvtm_u32_v, arm_neon_vcvtmu, 0),
634 NEONMAP1(vcvtm_u64_v, arm_neon_vcvtmu, 0),
635 NEONMAP1(vcvtmq_s16_f16, arm_neon_vcvtms, 0),
636 NEONMAP1(vcvtmq_s32_v, arm_neon_vcvtms, 0),
637 NEONMAP1(vcvtmq_s64_v, arm_neon_vcvtms, 0),
638 NEONMAP1(vcvtmq_u16_f16, arm_neon_vcvtmu, 0),
639 NEONMAP1(vcvtmq_u32_v, arm_neon_vcvtmu, 0),
640 NEONMAP1(vcvtmq_u64_v, arm_neon_vcvtmu, 0),
641 NEONMAP1(vcvtn_s16_f16, arm_neon_vcvtns, 0),
642 NEONMAP1(vcvtn_s32_v, arm_neon_vcvtns, 0),
643 NEONMAP1(vcvtn_s64_v, arm_neon_vcvtns, 0),
644 NEONMAP1(vcvtn_u16_f16, arm_neon_vcvtnu, 0),
645 NEONMAP1(vcvtn_u32_v, arm_neon_vcvtnu, 0),
646 NEONMAP1(vcvtn_u64_v, arm_neon_vcvtnu, 0),
647 NEONMAP1(vcvtnq_s16_f16, arm_neon_vcvtns, 0),
648 NEONMAP1(vcvtnq_s32_v, arm_neon_vcvtns, 0),
649 NEONMAP1(vcvtnq_s64_v, arm_neon_vcvtns, 0),
650 NEONMAP1(vcvtnq_u16_f16, arm_neon_vcvtnu, 0),
651 NEONMAP1(vcvtnq_u32_v, arm_neon_vcvtnu, 0),
652 NEONMAP1(vcvtnq_u64_v, arm_neon_vcvtnu, 0),
653 NEONMAP1(vcvtp_s16_f16, arm_neon_vcvtps, 0),
654 NEONMAP1(vcvtp_s32_v, arm_neon_vcvtps, 0),
655 NEONMAP1(vcvtp_s64_v, arm_neon_vcvtps, 0),
656 NEONMAP1(vcvtp_u16_f16, arm_neon_vcvtpu, 0),
657 NEONMAP1(vcvtp_u32_v, arm_neon_vcvtpu, 0),
658 NEONMAP1(vcvtp_u64_v, arm_neon_vcvtpu, 0),
659 NEONMAP1(vcvtpq_s16_f16, arm_neon_vcvtps, 0),
660 NEONMAP1(vcvtpq_s32_v, arm_neon_vcvtps, 0),
661 NEONMAP1(vcvtpq_s64_v, arm_neon_vcvtps, 0),
662 NEONMAP1(vcvtpq_u16_f16, arm_neon_vcvtpu, 0),
663 NEONMAP1(vcvtpq_u32_v, arm_neon_vcvtpu, 0),
664 NEONMAP1(vcvtpq_u64_v, arm_neon_vcvtpu, 0),
665 NEONMAP0(vcvtq_f16_s16),
666 NEONMAP0(vcvtq_f16_u16),
667 NEONMAP0(vcvtq_f32_v),
668 NEONMAP1(vcvtq_n_f16_s16, arm_neon_vcvtfxs2fp, 0),
669 NEONMAP1(vcvtq_n_f16_u16, arm_neon_vcvtfxu2fp, 0),
670 NEONMAP2(vcvtq_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
671 NEONMAP1(vcvtq_n_s16_f16, arm_neon_vcvtfp2fxs, 0),
672 NEONMAP1(vcvtq_n_s32_v, arm_neon_vcvtfp2fxs, 0),
673 NEONMAP1(vcvtq_n_s64_v, arm_neon_vcvtfp2fxs, 0),
674 NEONMAP1(vcvtq_n_u16_f16, arm_neon_vcvtfp2fxu, 0),
675 NEONMAP1(vcvtq_n_u32_v, arm_neon_vcvtfp2fxu, 0),
676 NEONMAP1(vcvtq_n_u64_v, arm_neon_vcvtfp2fxu, 0),
677 NEONMAP0(vcvtq_s16_f16),
678 NEONMAP0(vcvtq_s32_v),
679 NEONMAP0(vcvtq_s64_v),
680 NEONMAP0(vcvtq_u16_f16),
681 NEONMAP0(vcvtq_u32_v),
682 NEONMAP0(vcvtq_u64_v),
683 NEONMAP1(vdot_s32, arm_neon_sdot, 0),
684 NEONMAP1(vdot_u32, arm_neon_udot, 0),
685 NEONMAP1(vdotq_s32, arm_neon_sdot, 0),
686 NEONMAP1(vdotq_u32, arm_neon_udot, 0),
687 NEONMAP0(vext_v),
688 NEONMAP0(vextq_v),
689 NEONMAP0(vfma_v),
690 NEONMAP0(vfmaq_v),
691 NEONMAP2(vhadd_v, arm_neon_vhaddu, arm_neon_vhadds, Add1ArgType | UnsignedAlts),
692 NEONMAP2(vhaddq_v, arm_neon_vhaddu, arm_neon_vhadds, Add1ArgType | UnsignedAlts),
693 NEONMAP2(vhsub_v, arm_neon_vhsubu, arm_neon_vhsubs, Add1ArgType | UnsignedAlts),
694 NEONMAP2(vhsubq_v, arm_neon_vhsubu, arm_neon_vhsubs, Add1ArgType | UnsignedAlts),
695 NEONMAP0(vld1_dup_v),
696 NEONMAP1(vld1_v, arm_neon_vld1, 0),
697 NEONMAP1(vld1_x2_v, arm_neon_vld1x2, 0),
698 NEONMAP1(vld1_x3_v, arm_neon_vld1x3, 0),
699 NEONMAP1(vld1_x4_v, arm_neon_vld1x4, 0),
700 NEONMAP0(vld1q_dup_v),
701 NEONMAP1(vld1q_v, arm_neon_vld1, 0),
702 NEONMAP1(vld1q_x2_v, arm_neon_vld1x2, 0),
703 NEONMAP1(vld1q_x3_v, arm_neon_vld1x3, 0),
704 NEONMAP1(vld1q_x4_v, arm_neon_vld1x4, 0),
705 NEONMAP1(vld2_dup_v, arm_neon_vld2dup, 0),
706 NEONMAP1(vld2_lane_v, arm_neon_vld2lane, 0),
707 NEONMAP1(vld2_v, arm_neon_vld2, 0),
708 NEONMAP1(vld2q_dup_v, arm_neon_vld2dup, 0),
709 NEONMAP1(vld2q_lane_v, arm_neon_vld2lane, 0),
710 NEONMAP1(vld2q_v, arm_neon_vld2, 0),
711 NEONMAP1(vld3_dup_v, arm_neon_vld3dup, 0),
712 NEONMAP1(vld3_lane_v, arm_neon_vld3lane, 0),
713 NEONMAP1(vld3_v, arm_neon_vld3, 0),
714 NEONMAP1(vld3q_dup_v, arm_neon_vld3dup, 0),
715 NEONMAP1(vld3q_lane_v, arm_neon_vld3lane, 0),
716 NEONMAP1(vld3q_v, arm_neon_vld3, 0),
717 NEONMAP1(vld4_dup_v, arm_neon_vld4dup, 0),
718 NEONMAP1(vld4_lane_v, arm_neon_vld4lane, 0),
719 NEONMAP1(vld4_v, arm_neon_vld4, 0),
720 NEONMAP1(vld4q_dup_v, arm_neon_vld4dup, 0),
721 NEONMAP1(vld4q_lane_v, arm_neon_vld4lane, 0),
722 NEONMAP1(vld4q_v, arm_neon_vld4, 0),
723 NEONMAP2(vmax_v, arm_neon_vmaxu, arm_neon_vmaxs, Add1ArgType | UnsignedAlts),
724 NEONMAP1(vmaxnm_v, arm_neon_vmaxnm, Add1ArgType),
725 NEONMAP1(vmaxnmq_v, arm_neon_vmaxnm, Add1ArgType),
726 NEONMAP2(vmaxq_v, arm_neon_vmaxu, arm_neon_vmaxs, Add1ArgType | UnsignedAlts),
727 NEONMAP2(vmin_v, arm_neon_vminu, arm_neon_vmins, Add1ArgType | UnsignedAlts),
728 NEONMAP1(vminnm_v, arm_neon_vminnm, Add1ArgType),
729 NEONMAP1(vminnmq_v, arm_neon_vminnm, Add1ArgType),
730 NEONMAP2(vminq_v, arm_neon_vminu, arm_neon_vmins, Add1ArgType | UnsignedAlts),
731 NEONMAP1(vmmlaq_s32, arm_neon_smmla, 0),
732 NEONMAP1(vmmlaq_u32, arm_neon_ummla, 0),
733 NEONMAP0(vmovl_v),
734 NEONMAP0(vmovn_v),
735 NEONMAP1(vmul_v, arm_neon_vmulp, Add1ArgType),
736 NEONMAP0(vmull_v),
737 NEONMAP1(vmulq_v, arm_neon_vmulp, Add1ArgType),
738 NEONMAP2(vpadal_v, arm_neon_vpadalu, arm_neon_vpadals, UnsignedAlts),
739 NEONMAP2(vpadalq_v, arm_neon_vpadalu, arm_neon_vpadals, UnsignedAlts),
740 NEONMAP1(vpadd_v, arm_neon_vpadd, Add1ArgType),
741 NEONMAP2(vpaddl_v, arm_neon_vpaddlu, arm_neon_vpaddls, UnsignedAlts),
742 NEONMAP2(vpaddlq_v, arm_neon_vpaddlu, arm_neon_vpaddls, UnsignedAlts),
743 NEONMAP1(vpaddq_v, arm_neon_vpadd, Add1ArgType),
744 NEONMAP2(vpmax_v, arm_neon_vpmaxu, arm_neon_vpmaxs, Add1ArgType | UnsignedAlts),
745 NEONMAP2(vpmin_v, arm_neon_vpminu, arm_neon_vpmins, Add1ArgType | UnsignedAlts),
746 NEONMAP1(vqabs_v, arm_neon_vqabs, Add1ArgType),
747 NEONMAP1(vqabsq_v, arm_neon_vqabs, Add1ArgType),
748 NEONMAP2(vqadd_v, uadd_sat, sadd_sat, Add1ArgType | UnsignedAlts),
749 NEONMAP2(vqaddq_v, uadd_sat, sadd_sat, Add1ArgType | UnsignedAlts),
750 NEONMAP2(vqdmlal_v, arm_neon_vqdmull, sadd_sat, 0),
751 NEONMAP2(vqdmlsl_v, arm_neon_vqdmull, ssub_sat, 0),
752 NEONMAP1(vqdmulh_v, arm_neon_vqdmulh, Add1ArgType),
753 NEONMAP1(vqdmulhq_v, arm_neon_vqdmulh, Add1ArgType),
754 NEONMAP1(vqdmull_v, arm_neon_vqdmull, Add1ArgType),
755 NEONMAP2(vqmovn_v, arm_neon_vqmovnu, arm_neon_vqmovns, Add1ArgType | UnsignedAlts),
756 NEONMAP1(vqmovun_v, arm_neon_vqmovnsu, Add1ArgType),
757 NEONMAP1(vqneg_v, arm_neon_vqneg, Add1ArgType),
758 NEONMAP1(vqnegq_v, arm_neon_vqneg, Add1ArgType),
759 NEONMAP1(vqrdmlah_s16, arm_neon_vqrdmlah, Add1ArgType),
760 NEONMAP1(vqrdmlah_s32, arm_neon_vqrdmlah, Add1ArgType),
761 NEONMAP1(vqrdmlahq_s16, arm_neon_vqrdmlah, Add1ArgType),
762 NEONMAP1(vqrdmlahq_s32, arm_neon_vqrdmlah, Add1ArgType),
763 NEONMAP1(vqrdmlsh_s16, arm_neon_vqrdmlsh, Add1ArgType),
764 NEONMAP1(vqrdmlsh_s32, arm_neon_vqrdmlsh, Add1ArgType),
765 NEONMAP1(vqrdmlshq_s16, arm_neon_vqrdmlsh, Add1ArgType),
766 NEONMAP1(vqrdmlshq_s32, arm_neon_vqrdmlsh, Add1ArgType),
767 NEONMAP1(vqrdmulh_v, arm_neon_vqrdmulh, Add1ArgType),
768 NEONMAP1(vqrdmulhq_v, arm_neon_vqrdmulh, Add1ArgType),
769 NEONMAP2(vqrshl_v, arm_neon_vqrshiftu, arm_neon_vqrshifts, Add1ArgType | UnsignedAlts),
770 NEONMAP2(vqrshlq_v, arm_neon_vqrshiftu, arm_neon_vqrshifts, Add1ArgType | UnsignedAlts),
771 NEONMAP2(vqshl_n_v, arm_neon_vqshiftu, arm_neon_vqshifts, UnsignedAlts),
772 NEONMAP2(vqshl_v, arm_neon_vqshiftu, arm_neon_vqshifts, Add1ArgType | UnsignedAlts),
773 NEONMAP2(vqshlq_n_v, arm_neon_vqshiftu, arm_neon_vqshifts, UnsignedAlts),
774 NEONMAP2(vqshlq_v, arm_neon_vqshiftu, arm_neon_vqshifts, Add1ArgType | UnsignedAlts),
775 NEONMAP1(vqshlu_n_v, arm_neon_vqshiftsu, 0),
776 NEONMAP1(vqshluq_n_v, arm_neon_vqshiftsu, 0),
777 NEONMAP2(vqsub_v, usub_sat, ssub_sat, Add1ArgType | UnsignedAlts),
778 NEONMAP2(vqsubq_v, usub_sat, ssub_sat, Add1ArgType | UnsignedAlts),
779 NEONMAP1(vraddhn_v, arm_neon_vraddhn, Add1ArgType),
780 NEONMAP2(vrecpe_v, arm_neon_vrecpe, arm_neon_vrecpe, 0),
781 NEONMAP2(vrecpeq_v, arm_neon_vrecpe, arm_neon_vrecpe, 0),
782 NEONMAP1(vrecps_v, arm_neon_vrecps, Add1ArgType),
783 NEONMAP1(vrecpsq_v, arm_neon_vrecps, Add1ArgType),
784 NEONMAP2(vrhadd_v, arm_neon_vrhaddu, arm_neon_vrhadds, Add1ArgType | UnsignedAlts),
785 NEONMAP2(vrhaddq_v, arm_neon_vrhaddu, arm_neon_vrhadds, Add1ArgType | UnsignedAlts),
786 NEONMAP1(vrnd_v, trunc, Add1ArgType),
787 NEONMAP1(vrnda_v, round, Add1ArgType),
788 NEONMAP1(vrndaq_v, round, Add1ArgType),
789 NEONMAP0(vrndi_v),
790 NEONMAP0(vrndiq_v),
791 NEONMAP1(vrndm_v, floor, Add1ArgType),
792 NEONMAP1(vrndmq_v, floor, Add1ArgType),
793 NEONMAP1(vrndn_v, roundeven, Add1ArgType),
794 NEONMAP1(vrndnq_v, roundeven, Add1ArgType),
795 NEONMAP1(vrndp_v, ceil, Add1ArgType),
796 NEONMAP1(vrndpq_v, ceil, Add1ArgType),
797 NEONMAP1(vrndq_v, trunc, Add1ArgType),
798 NEONMAP1(vrndx_v, rint, Add1ArgType),
799 NEONMAP1(vrndxq_v, rint, Add1ArgType),
800 NEONMAP2(vrshl_v, arm_neon_vrshiftu, arm_neon_vrshifts, Add1ArgType | UnsignedAlts),
801 NEONMAP2(vrshlq_v, arm_neon_vrshiftu, arm_neon_vrshifts, Add1ArgType | UnsignedAlts),
802 NEONMAP2(vrshr_n_v, arm_neon_vrshiftu, arm_neon_vrshifts, UnsignedAlts),
803 NEONMAP2(vrshrq_n_v, arm_neon_vrshiftu, arm_neon_vrshifts, UnsignedAlts),
804 NEONMAP2(vrsqrte_v, arm_neon_vrsqrte, arm_neon_vrsqrte, 0),
805 NEONMAP2(vrsqrteq_v, arm_neon_vrsqrte, arm_neon_vrsqrte, 0),
806 NEONMAP1(vrsqrts_v, arm_neon_vrsqrts, Add1ArgType),
807 NEONMAP1(vrsqrtsq_v, arm_neon_vrsqrts, Add1ArgType),
808 NEONMAP1(vrsubhn_v, arm_neon_vrsubhn, Add1ArgType),
809 NEONMAP1(vsha1su0q_u32, arm_neon_sha1su0, 0),
810 NEONMAP1(vsha1su1q_u32, arm_neon_sha1su1, 0),
811 NEONMAP1(vsha256h2q_u32, arm_neon_sha256h2, 0),
812 NEONMAP1(vsha256hq_u32, arm_neon_sha256h, 0),
813 NEONMAP1(vsha256su0q_u32, arm_neon_sha256su0, 0),
814 NEONMAP1(vsha256su1q_u32, arm_neon_sha256su1, 0),
815 NEONMAP0(vshl_n_v),
816 NEONMAP2(vshl_v, arm_neon_vshiftu, arm_neon_vshifts, Add1ArgType | UnsignedAlts),
817 NEONMAP0(vshll_n_v),
818 NEONMAP0(vshlq_n_v),
819 NEONMAP2(vshlq_v, arm_neon_vshiftu, arm_neon_vshifts, Add1ArgType | UnsignedAlts),
820 NEONMAP0(vshr_n_v),
821 NEONMAP0(vshrn_n_v),
822 NEONMAP0(vshrq_n_v),
823 NEONMAP1(vst1_v, arm_neon_vst1, 0),
824 NEONMAP1(vst1_x2_v, arm_neon_vst1x2, 0),
825 NEONMAP1(vst1_x3_v, arm_neon_vst1x3, 0),
826 NEONMAP1(vst1_x4_v, arm_neon_vst1x4, 0),
827 NEONMAP1(vst1q_v, arm_neon_vst1, 0),
828 NEONMAP1(vst1q_x2_v, arm_neon_vst1x2, 0),
829 NEONMAP1(vst1q_x3_v, arm_neon_vst1x3, 0),
830 NEONMAP1(vst1q_x4_v, arm_neon_vst1x4, 0),
831 NEONMAP1(vst2_lane_v, arm_neon_vst2lane, 0),
832 NEONMAP1(vst2_v, arm_neon_vst2, 0),
833 NEONMAP1(vst2q_lane_v, arm_neon_vst2lane, 0),
834 NEONMAP1(vst2q_v, arm_neon_vst2, 0),
835 NEONMAP1(vst3_lane_v, arm_neon_vst3lane, 0),
836 NEONMAP1(vst3_v, arm_neon_vst3, 0),
837 NEONMAP1(vst3q_lane_v, arm_neon_vst3lane, 0),
838 NEONMAP1(vst3q_v, arm_neon_vst3, 0),
839 NEONMAP1(vst4_lane_v, arm_neon_vst4lane, 0),
840 NEONMAP1(vst4_v, arm_neon_vst4, 0),
841 NEONMAP1(vst4q_lane_v, arm_neon_vst4lane, 0),
842 NEONMAP1(vst4q_v, arm_neon_vst4, 0),
843 NEONMAP0(vsubhn_v),
844 NEONMAP0(vtrn_v),
845 NEONMAP0(vtrnq_v),
846 NEONMAP0(vtst_v),
847 NEONMAP0(vtstq_v),
848 NEONMAP1(vusdot_s32, arm_neon_usdot, 0),
849 NEONMAP1(vusdotq_s32, arm_neon_usdot, 0),
850 NEONMAP1(vusmmlaq_s32, arm_neon_usmmla, 0),
851 NEONMAP0(vuzp_v),
852 NEONMAP0(vuzpq_v),
853 NEONMAP0(vzip_v),
854 NEONMAP0(vzipq_v)
855};
856
857// clang-format on
858
859// Some intrinsics are equivalent for codegen.
860static const std::pair<unsigned, unsigned> NEONEquivalentIntrinsicMap[] = {
861 { NEON::BI__builtin_neon_vabd_f16, NEON::BI__builtin_neon_vabd_v, },
862 { NEON::BI__builtin_neon_vabdq_f16, NEON::BI__builtin_neon_vabdq_v, },
863 { NEON::BI__builtin_neon_vabs_f16, NEON::BI__builtin_neon_vabs_v, },
864 { NEON::BI__builtin_neon_vabsq_f16, NEON::BI__builtin_neon_vabsq_v, },
865 { NEON::BI__builtin_neon_vcage_f16, NEON::BI__builtin_neon_vcage_v, },
866 { NEON::BI__builtin_neon_vcageq_f16, NEON::BI__builtin_neon_vcageq_v, },
867 { NEON::BI__builtin_neon_vcagt_f16, NEON::BI__builtin_neon_vcagt_v, },
868 { NEON::BI__builtin_neon_vcagtq_f16, NEON::BI__builtin_neon_vcagtq_v, },
869 { NEON::BI__builtin_neon_vcale_f16, NEON::BI__builtin_neon_vcale_v, },
870 { NEON::BI__builtin_neon_vcaleq_f16, NEON::BI__builtin_neon_vcaleq_v, },
871 { NEON::BI__builtin_neon_vcalt_f16, NEON::BI__builtin_neon_vcalt_v, },
872 { NEON::BI__builtin_neon_vcaltq_f16, NEON::BI__builtin_neon_vcaltq_v, },
873 { NEON::BI__builtin_neon_vceqz_f16, NEON::BI__builtin_neon_vceqz_v, },
874 { NEON::BI__builtin_neon_vceqzq_f16, NEON::BI__builtin_neon_vceqzq_v, },
875 { NEON::BI__builtin_neon_vcgez_f16, NEON::BI__builtin_neon_vcgez_v, },
876 { NEON::BI__builtin_neon_vcgezq_f16, NEON::BI__builtin_neon_vcgezq_v, },
877 { NEON::BI__builtin_neon_vcgtz_f16, NEON::BI__builtin_neon_vcgtz_v, },
878 { NEON::BI__builtin_neon_vcgtzq_f16, NEON::BI__builtin_neon_vcgtzq_v, },
879 { NEON::BI__builtin_neon_vclez_f16, NEON::BI__builtin_neon_vclez_v, },
880 { NEON::BI__builtin_neon_vclezq_f16, NEON::BI__builtin_neon_vclezq_v, },
881 { NEON::BI__builtin_neon_vcltz_f16, NEON::BI__builtin_neon_vcltz_v, },
882 { NEON::BI__builtin_neon_vcltzq_f16, NEON::BI__builtin_neon_vcltzq_v, },
883 { NEON::BI__builtin_neon_vfma_f16, NEON::BI__builtin_neon_vfma_v, },
884 { NEON::BI__builtin_neon_vfma_lane_f16, NEON::BI__builtin_neon_vfma_lane_v, },
885 { NEON::BI__builtin_neon_vfma_laneq_f16, NEON::BI__builtin_neon_vfma_laneq_v, },
886 { NEON::BI__builtin_neon_vfmaq_f16, NEON::BI__builtin_neon_vfmaq_v, },
887 { NEON::BI__builtin_neon_vfmaq_lane_f16, NEON::BI__builtin_neon_vfmaq_lane_v, },
888 { NEON::BI__builtin_neon_vfmaq_laneq_f16, NEON::BI__builtin_neon_vfmaq_laneq_v, },
889 { NEON::BI__builtin_neon_vmax_f16, NEON::BI__builtin_neon_vmax_v, },
890 { NEON::BI__builtin_neon_vmaxnm_f16, NEON::BI__builtin_neon_vmaxnm_v, },
891 { NEON::BI__builtin_neon_vmaxnmq_f16, NEON::BI__builtin_neon_vmaxnmq_v, },
892 { NEON::BI__builtin_neon_vmaxq_f16, NEON::BI__builtin_neon_vmaxq_v, },
893 { NEON::BI__builtin_neon_vmin_f16, NEON::BI__builtin_neon_vmin_v, },
894 { NEON::BI__builtin_neon_vminnm_f16, NEON::BI__builtin_neon_vminnm_v, },
895 { NEON::BI__builtin_neon_vminnmq_f16, NEON::BI__builtin_neon_vminnmq_v, },
896 { NEON::BI__builtin_neon_vminq_f16, NEON::BI__builtin_neon_vminq_v, },
897 { NEON::BI__builtin_neon_vmulx_f16, NEON::BI__builtin_neon_vmulx_v, },
898 { NEON::BI__builtin_neon_vmulxq_f16, NEON::BI__builtin_neon_vmulxq_v, },
899 { NEON::BI__builtin_neon_vpadd_f16, NEON::BI__builtin_neon_vpadd_v, },
900 { NEON::BI__builtin_neon_vpaddq_f16, NEON::BI__builtin_neon_vpaddq_v, },
901 { NEON::BI__builtin_neon_vpmax_f16, NEON::BI__builtin_neon_vpmax_v, },
902 { NEON::BI__builtin_neon_vpmaxnm_f16, NEON::BI__builtin_neon_vpmaxnm_v, },
903 { NEON::BI__builtin_neon_vpmaxnmq_f16, NEON::BI__builtin_neon_vpmaxnmq_v, },
904 { NEON::BI__builtin_neon_vpmaxq_f16, NEON::BI__builtin_neon_vpmaxq_v, },
905 { NEON::BI__builtin_neon_vpmin_f16, NEON::BI__builtin_neon_vpmin_v, },
906 { NEON::BI__builtin_neon_vpminnm_f16, NEON::BI__builtin_neon_vpminnm_v, },
907 { NEON::BI__builtin_neon_vpminnmq_f16, NEON::BI__builtin_neon_vpminnmq_v, },
908 { NEON::BI__builtin_neon_vpminq_f16, NEON::BI__builtin_neon_vpminq_v, },
909 { NEON::BI__builtin_neon_vrecpe_f16, NEON::BI__builtin_neon_vrecpe_v, },
910 { NEON::BI__builtin_neon_vrecpeq_f16, NEON::BI__builtin_neon_vrecpeq_v, },
911 { NEON::BI__builtin_neon_vrecps_f16, NEON::BI__builtin_neon_vrecps_v, },
912 { NEON::BI__builtin_neon_vrecpsq_f16, NEON::BI__builtin_neon_vrecpsq_v, },
913 { NEON::BI__builtin_neon_vrnd_f16, NEON::BI__builtin_neon_vrnd_v, },
914 { NEON::BI__builtin_neon_vrnda_f16, NEON::BI__builtin_neon_vrnda_v, },
915 { NEON::BI__builtin_neon_vrndaq_f16, NEON::BI__builtin_neon_vrndaq_v, },
916 { NEON::BI__builtin_neon_vrndi_f16, NEON::BI__builtin_neon_vrndi_v, },
917 { NEON::BI__builtin_neon_vrndiq_f16, NEON::BI__builtin_neon_vrndiq_v, },
918 { NEON::BI__builtin_neon_vrndm_f16, NEON::BI__builtin_neon_vrndm_v, },
919 { NEON::BI__builtin_neon_vrndmq_f16, NEON::BI__builtin_neon_vrndmq_v, },
920 { NEON::BI__builtin_neon_vrndn_f16, NEON::BI__builtin_neon_vrndn_v, },
921 { NEON::BI__builtin_neon_vrndnq_f16, NEON::BI__builtin_neon_vrndnq_v, },
922 { NEON::BI__builtin_neon_vrndp_f16, NEON::BI__builtin_neon_vrndp_v, },
923 { NEON::BI__builtin_neon_vrndpq_f16, NEON::BI__builtin_neon_vrndpq_v, },
924 { NEON::BI__builtin_neon_vrndq_f16, NEON::BI__builtin_neon_vrndq_v, },
925 { NEON::BI__builtin_neon_vrndx_f16, NEON::BI__builtin_neon_vrndx_v, },
926 { NEON::BI__builtin_neon_vrndxq_f16, NEON::BI__builtin_neon_vrndxq_v, },
927 { NEON::BI__builtin_neon_vrsqrte_f16, NEON::BI__builtin_neon_vrsqrte_v, },
928 { NEON::BI__builtin_neon_vrsqrteq_f16, NEON::BI__builtin_neon_vrsqrteq_v, },
929 { NEON::BI__builtin_neon_vrsqrts_f16, NEON::BI__builtin_neon_vrsqrts_v, },
930 { NEON::BI__builtin_neon_vrsqrtsq_f16, NEON::BI__builtin_neon_vrsqrtsq_v, },
931 { NEON::BI__builtin_neon_vsqrt_f16, NEON::BI__builtin_neon_vsqrt_v, },
932 { NEON::BI__builtin_neon_vsqrtq_f16, NEON::BI__builtin_neon_vsqrtq_v, },
933 // The mangling rules cause us to have one ID for each type for vldap1(q)_lane
934 // and vstl1(q)_lane, but codegen is equivalent for all of them. Choose an
935 // arbitrary one to be handled as tha canonical variation.
936 { NEON::BI__builtin_neon_vldap1_lane_u64, NEON::BI__builtin_neon_vldap1_lane_s64 },
937 { NEON::BI__builtin_neon_vldap1_lane_f64, NEON::BI__builtin_neon_vldap1_lane_s64 },
938 { NEON::BI__builtin_neon_vldap1_lane_p64, NEON::BI__builtin_neon_vldap1_lane_s64 },
939 { NEON::BI__builtin_neon_vldap1q_lane_u64, NEON::BI__builtin_neon_vldap1q_lane_s64 },
940 { NEON::BI__builtin_neon_vldap1q_lane_f64, NEON::BI__builtin_neon_vldap1q_lane_s64 },
941 { NEON::BI__builtin_neon_vldap1q_lane_p64, NEON::BI__builtin_neon_vldap1q_lane_s64 },
942 { NEON::BI__builtin_neon_vstl1_lane_u64, NEON::BI__builtin_neon_vstl1_lane_s64 },
943 { NEON::BI__builtin_neon_vstl1_lane_f64, NEON::BI__builtin_neon_vstl1_lane_s64 },
944 { NEON::BI__builtin_neon_vstl1_lane_p64, NEON::BI__builtin_neon_vstl1_lane_s64 },
945 { NEON::BI__builtin_neon_vstl1q_lane_u64, NEON::BI__builtin_neon_vstl1q_lane_s64 },
946 { NEON::BI__builtin_neon_vstl1q_lane_f64, NEON::BI__builtin_neon_vstl1q_lane_s64 },
947 { NEON::BI__builtin_neon_vstl1q_lane_p64, NEON::BI__builtin_neon_vstl1q_lane_s64 },
948};
949
950#undef NEONMAP0
951#undef NEONMAP1
952#undef NEONMAP2
953
954#define SVEMAP1(NameBase, LLVMIntrinsic, TypeModifier) \
955 {SVE::BI__builtin_sve_##NameBase, Intrinsic::LLVMIntrinsic, TypeModifier}
956
957#define SVEMAP2(NameBase, TypeModifier) \
958 {SVE::BI__builtin_sve_##NameBase, 0, TypeModifier}
959static const AArch64SVEAndSMEVectorIntrinsicInfo AArch64SVEIntrinsicMap[] = {
960#define GET_SVE_LLVM_INTRINSIC_MAP
961#include "clang/Basic/arm_sve_builtin_cg.inc"
962#include "clang/Basic/BuiltinsAArch64NeonSVEBridge_cg.def"
963#undef GET_SVE_LLVM_INTRINSIC_MAP
964};
965
966#undef SVEMAP1
967#undef SVEMAP2
968
969#define SMEMAP1(NameBase, LLVMIntrinsic, TypeModifier) \
970 {SME::BI__builtin_sme_##NameBase, Intrinsic::LLVMIntrinsic, TypeModifier}
971
972#define SMEMAP2(NameBase, TypeModifier) \
973 {SME::BI__builtin_sme_##NameBase, 0, TypeModifier}
974static const AArch64SVEAndSMEVectorIntrinsicInfo AArch64SMEIntrinsicMap[] = {
975#define GET_SME_LLVM_INTRINSIC_MAP
976#include "clang/Basic/arm_sme_builtin_cg.inc"
977#undef GET_SME_LLVM_INTRINSIC_MAP
978};
979
980#undef SMEMAP1
981#undef SMEMAP2
982
983static bool NEONSIMDIntrinsicsProvenSorted = false;
984
985static bool AArch64SIMDIntrinsicsProvenSorted = false;
986static bool AArch64SISDIntrinsicsProvenSorted = false;
987static bool AArch64SVEIntrinsicsProvenSorted = false;
988static bool AArch64SMEIntrinsicsProvenSorted = false;
989
990// Check if Builtin `BuiltinId` is present in `IntrinsicMap`. If yes, returns
991// the corresponding info struct.
992template <typename IntrinsicInfo>
993static const IntrinsicInfo *
994findARMVectorIntrinsicInMap(ArrayRef<IntrinsicInfo> IntrinsicMap,
995 unsigned BuiltinID, bool &MapProvenSorted) {
996
997#ifndef NDEBUG
998 if (!MapProvenSorted) {
999 assert(llvm::is_sorted(IntrinsicMap));
1000 MapProvenSorted = true;
1001 }
1002#endif
1003
1004 const IntrinsicInfo *Builtin = llvm::lower_bound(IntrinsicMap, BuiltinID);
1005
1006 if (Builtin != IntrinsicMap.end() && Builtin->BuiltinID == BuiltinID)
1007 return Builtin;
1008
1009 return nullptr;
1010}
1011
1012Function *CodeGenFunction::LookupNeonLLVMIntrinsic(unsigned IntrinsicID,
1013 unsigned Modifier,
1014 llvm::Type *ArgType,
1015 const CallExpr *E) {
1016 int VectorSize = 0;
1017 if (Modifier & Use64BitVectors)
1018 VectorSize = 64;
1019 else if (Modifier & Use128BitVectors)
1020 VectorSize = 128;
1021
1022 // Return type.
1023 SmallVector<llvm::Type *, 3> Tys;
1024 if (Modifier & AddRetType) {
1025 llvm::Type *Ty = ConvertType(T: E->getCallReturnType(Ctx: getContext()));
1026 if (Modifier & VectorizeRetType)
1027 Ty = llvm::FixedVectorType::get(
1028 ElementType: Ty, NumElts: VectorSize ? VectorSize / Ty->getPrimitiveSizeInBits() : 1);
1029
1030 Tys.push_back(Elt: Ty);
1031 }
1032
1033 // Arguments.
1034 if (Modifier & VectorizeArgTypes) {
1035 int Elts = VectorSize ? VectorSize / ArgType->getPrimitiveSizeInBits() : 1;
1036 ArgType = llvm::FixedVectorType::get(ElementType: ArgType, NumElts: Elts);
1037 }
1038
1039 if (Modifier & (Add1ArgType | Add2ArgTypes))
1040 Tys.push_back(Elt: ArgType);
1041
1042 if (Modifier & Add2ArgTypes)
1043 Tys.push_back(Elt: ArgType);
1044
1045 if (Modifier & InventFloatType)
1046 Tys.push_back(Elt: FloatTy);
1047
1048 return CGM.getIntrinsic(IID: IntrinsicID, Tys);
1049}
1050
1051//===----------------------------------------------------------------------===//
1052// Emit-helpers
1053//===----------------------------------------------------------------------===//
1054static Value *EmitCommonNeonSISDBuiltinExpr(
1055 CodeGenFunction &CGF, const ARMNeonVectorIntrinsicInfo &SISDInfo,
1056 SmallVectorImpl<Value *> &Ops, const CallExpr *E) {
1057 assert(SISDInfo.LLVMIntrinsic && "Generic code assumes a valid intrinsic");
1058
1059 switch (SISDInfo.BuiltinID) {
1060 case NEON::BI__builtin_neon_vcled_s64:
1061 case NEON::BI__builtin_neon_vcled_u64:
1062 case NEON::BI__builtin_neon_vcles_f32:
1063 case NEON::BI__builtin_neon_vcled_f64:
1064 case NEON::BI__builtin_neon_vcltd_s64:
1065 case NEON::BI__builtin_neon_vcltd_u64:
1066 case NEON::BI__builtin_neon_vclts_f32:
1067 case NEON::BI__builtin_neon_vcltd_f64:
1068 case NEON::BI__builtin_neon_vcales_f32:
1069 case NEON::BI__builtin_neon_vcaled_f64:
1070 case NEON::BI__builtin_neon_vcalts_f32:
1071 case NEON::BI__builtin_neon_vcaltd_f64:
1072 // Only one direction of comparisons actually exist, cmle is actually a cmge
1073 // with swapped operands. The table gives us the right intrinsic but we
1074 // still need to do the swap.
1075 std::swap(a&: Ops[0], b&: Ops[1]);
1076 break;
1077 }
1078
1079 // Use fptosi.sat/fptoui.sat unless under strict FP.
1080 unsigned LLVMIntrinsic = SISDInfo.LLVMIntrinsic;
1081 if (!CGF.Builder.getIsFPConstrained()) {
1082 if (LLVMIntrinsic == Intrinsic::aarch64_neon_fcvtzs)
1083 LLVMIntrinsic = Intrinsic::fptosi_sat;
1084 else if (LLVMIntrinsic == Intrinsic::aarch64_neon_fcvtzu)
1085 LLVMIntrinsic = Intrinsic::fptoui_sat;
1086 }
1087 llvm::Type *ArgTy = CGF.ConvertType(T: E->getArg(Arg: 0)->getType());
1088 Function *F = CGF.LookupNeonLLVMIntrinsic(IntrinsicID: LLVMIntrinsic,
1089 Modifier: SISDInfo.TypeModifier, ArgType: ArgTy, E);
1090
1091 int j = 0;
1092 ConstantInt *C0 = ConstantInt::get(Ty: CGF.SizeTy, V: 0);
1093 for (Function::const_arg_iterator ai = F->arg_begin(), ae = F->arg_end();
1094 ai != ae; ++ai, ++j) {
1095 llvm::Type *ArgTy = ai->getType();
1096 if (Ops[j]->getType()->getPrimitiveSizeInBits() ==
1097 ArgTy->getPrimitiveSizeInBits())
1098 continue;
1099 assert(
1100 ArgTy->isVectorTy() && !Ops[j]->getType()->isVectorTy() &&
1101 "Expecting vector LLVM intrinsic type and scalar Clang builtin type!");
1102
1103 // The constant argument to an _n_ intrinsic always has Int32Ty, so truncate
1104 // it before inserting.
1105 Ops[j] = CGF.Builder.CreateTruncOrBitCast(
1106 V: Ops[j], DestTy: cast<llvm::VectorType>(Val: ArgTy)->getElementType());
1107 Ops[j] =
1108 CGF.Builder.CreateInsertElement(Vec: PoisonValue::get(T: ArgTy), NewElt: Ops[j], Idx: C0);
1109 }
1110
1111 Value *Result = CGF.EmitNeonCall(F, Ops, name: SISDInfo.NameHint);
1112 llvm::Type *ResultType = CGF.ConvertType(T: E->getType());
1113 if (ResultType->getPrimitiveSizeInBits().getFixedValue() <
1114 Result->getType()->getPrimitiveSizeInBits().getFixedValue())
1115 return CGF.Builder.CreateExtractElement(Vec: Result, Idx: C0);
1116
1117 return CGF.Builder.CreateBitCast(V: Result, DestTy: ResultType, Name: SISDInfo.NameHint);
1118}
1119
1120Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
1121 unsigned BuiltinID, unsigned LLVMIntrinsic, unsigned AltLLVMIntrinsic,
1122 const char *NameHint, unsigned Modifier, const CallExpr *E,
1123 SmallVectorImpl<llvm::Value *> &Ops, Address PtrOp0, Address PtrOp1,
1124 llvm::Triple::ArchType Arch) {
1125
1126 // Extract the trailing immediate argument that encodes the type discriminator
1127 // for this overloaded intrinsic.
1128 // TODO: Move to the parent code that takes care of argument processing.
1129 const Expr *Arg = E->getArg(Arg: E->getNumArgs() - 1);
1130 std::optional<llvm::APSInt> NeonTypeConst =
1131 Arg->getIntegerConstantExpr(Ctx: getContext());
1132 if (!NeonTypeConst)
1133 return nullptr;
1134
1135 // Determine the type of this overloaded NEON intrinsic.
1136 NeonTypeFlags Type(NeonTypeConst->getZExtValue());
1137 const bool Usgn = Type.isUnsigned();
1138 const bool Quad = Type.isQuad();
1139 const bool Floating = Type.isFloatingPoint();
1140 const bool HasFastHalfType = getTarget().hasFastHalfType();
1141 const bool AllowBFloatArgsAndRet =
1142 getTargetHooks().getABIInfo().allowBFloatArgsAndRet();
1143
1144 llvm::FixedVectorType *VTy =
1145 GetNeonType(CGF: this, TypeFlags: Type, HasFastHalfType, V1Ty: false, AllowBFloatArgsAndRet);
1146 llvm::Type *Ty = VTy;
1147 if (!Ty)
1148 return nullptr;
1149
1150 auto getAlignmentValue32 = [&](Address addr) -> Value* {
1151 return Builder.getInt32(C: addr.getAlignment().getQuantity());
1152 };
1153
1154 unsigned Int = LLVMIntrinsic;
1155 if ((Modifier & UnsignedAlts) && !Usgn)
1156 Int = AltLLVMIntrinsic;
1157
1158 switch (BuiltinID) {
1159 default: break;
1160 case NEON::BI__builtin_neon_splat_lane_v:
1161 case NEON::BI__builtin_neon_splat_laneq_v:
1162 case NEON::BI__builtin_neon_splatq_lane_v:
1163 case NEON::BI__builtin_neon_splatq_laneq_v: {
1164 auto NumElements = VTy->getElementCount();
1165 if (BuiltinID == NEON::BI__builtin_neon_splatq_lane_v)
1166 NumElements = NumElements * 2;
1167 if (BuiltinID == NEON::BI__builtin_neon_splat_laneq_v)
1168 NumElements = NumElements.divideCoefficientBy(RHS: 2);
1169
1170 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: VTy);
1171 return EmitNeonSplat(V: Ops[0], C: cast<ConstantInt>(Val: Ops[1]), Count: NumElements);
1172 }
1173 case NEON::BI__builtin_neon_vpadd_v:
1174 case NEON::BI__builtin_neon_vpaddq_v:
1175 // We don't allow fp/int overloading of intrinsics.
1176 if (VTy->getElementType()->isFloatingPointTy() &&
1177 Int == Intrinsic::aarch64_neon_addp)
1178 Int = Intrinsic::aarch64_neon_faddp;
1179 break;
1180 case NEON::BI__builtin_neon_vabs_v:
1181 case NEON::BI__builtin_neon_vabsq_v:
1182 if (VTy->getElementType()->isFloatingPointTy())
1183 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::fabs, Tys: Ty), Ops, name: "vabs");
1184 return EmitNeonCall(F: CGM.getIntrinsic(IID: LLVMIntrinsic, Tys: Ty), Ops, name: "vabs");
1185 case NEON::BI__builtin_neon_vadd_v:
1186 case NEON::BI__builtin_neon_vaddq_v: {
1187 llvm::Type *VTy = llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: Quad ? 16 : 8);
1188 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: VTy);
1189 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: VTy);
1190 Ops[0] = Builder.CreateXor(LHS: Ops[0], RHS: Ops[1]);
1191 return Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
1192 }
1193 case NEON::BI__builtin_neon_vaddhn_v: {
1194 llvm::FixedVectorType *SrcTy =
1195 llvm::FixedVectorType::getExtendedElementVectorType(VTy);
1196
1197 // %sum = add <4 x i32> %lhs, %rhs
1198 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: SrcTy);
1199 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: SrcTy);
1200 Ops[0] = Builder.CreateAdd(LHS: Ops[0], RHS: Ops[1], Name: "vaddhn");
1201
1202 // %high = lshr <4 x i32> %sum, <i32 16, i32 16, i32 16, i32 16>
1203 Constant *ShiftAmt =
1204 ConstantInt::get(Ty: SrcTy, V: SrcTy->getScalarSizeInBits() / 2);
1205 Ops[0] = Builder.CreateLShr(LHS: Ops[0], RHS: ShiftAmt, Name: "vaddhn");
1206
1207 // %res = trunc <4 x i32> %high to <4 x i16>
1208 return Builder.CreateTrunc(V: Ops[0], DestTy: VTy, Name: "vaddhn");
1209 }
1210 case NEON::BI__builtin_neon_vcale_v:
1211 case NEON::BI__builtin_neon_vcaleq_v:
1212 case NEON::BI__builtin_neon_vcalt_v:
1213 case NEON::BI__builtin_neon_vcaltq_v:
1214 std::swap(a&: Ops[0], b&: Ops[1]);
1215 [[fallthrough]];
1216 case NEON::BI__builtin_neon_vcage_v:
1217 case NEON::BI__builtin_neon_vcageq_v:
1218 case NEON::BI__builtin_neon_vcagt_v:
1219 case NEON::BI__builtin_neon_vcagtq_v: {
1220 llvm::Type *Ty;
1221 switch (VTy->getScalarSizeInBits()) {
1222 default: llvm_unreachable("unexpected type");
1223 case 32:
1224 Ty = FloatTy;
1225 break;
1226 case 64:
1227 Ty = DoubleTy;
1228 break;
1229 case 16:
1230 Ty = HalfTy;
1231 break;
1232 }
1233 auto *VecFlt = llvm::FixedVectorType::get(ElementType: Ty, NumElts: VTy->getNumElements());
1234 llvm::Type *Tys[] = { VTy, VecFlt };
1235 Function *F = CGM.getIntrinsic(IID: LLVMIntrinsic, Tys);
1236 return EmitNeonCall(F, Ops, name: NameHint);
1237 }
1238 case NEON::BI__builtin_neon_vceqz_v:
1239 case NEON::BI__builtin_neon_vceqzq_v:
1240 return EmitAArch64CompareBuiltinExpr(
1241 Op: Ops[0], Ty, Pred: Floating ? ICmpInst::FCMP_OEQ : ICmpInst::ICMP_EQ, Name: "vceqz");
1242 case NEON::BI__builtin_neon_vcgez_v:
1243 case NEON::BI__builtin_neon_vcgezq_v:
1244 return EmitAArch64CompareBuiltinExpr(
1245 Op: Ops[0], Ty, Pred: Floating ? ICmpInst::FCMP_OGE : ICmpInst::ICMP_SGE,
1246 Name: "vcgez");
1247 case NEON::BI__builtin_neon_vclez_v:
1248 case NEON::BI__builtin_neon_vclezq_v:
1249 return EmitAArch64CompareBuiltinExpr(
1250 Op: Ops[0], Ty, Pred: Floating ? ICmpInst::FCMP_OLE : ICmpInst::ICMP_SLE,
1251 Name: "vclez");
1252 case NEON::BI__builtin_neon_vcgtz_v:
1253 case NEON::BI__builtin_neon_vcgtzq_v:
1254 return EmitAArch64CompareBuiltinExpr(
1255 Op: Ops[0], Ty, Pred: Floating ? ICmpInst::FCMP_OGT : ICmpInst::ICMP_SGT,
1256 Name: "vcgtz");
1257 case NEON::BI__builtin_neon_vcltz_v:
1258 case NEON::BI__builtin_neon_vcltzq_v:
1259 return EmitAArch64CompareBuiltinExpr(
1260 Op: Ops[0], Ty, Pred: Floating ? ICmpInst::FCMP_OLT : ICmpInst::ICMP_SLT,
1261 Name: "vcltz");
1262 case NEON::BI__builtin_neon_vclz_v:
1263 case NEON::BI__builtin_neon_vclzq_v:
1264 // We generate target-independent intrinsic, which needs a second argument
1265 // for whether or not clz of zero is undefined; on ARM it isn't.
1266 Ops.push_back(Elt: Builder.getInt1(V: getTarget().isCLZForZeroUndef()));
1267 break;
1268 case NEON::BI__builtin_neon_vcvt_f32_v:
1269 case NEON::BI__builtin_neon_vcvtq_f32_v:
1270 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
1271 Ty = GetNeonType(CGF: this, TypeFlags: NeonTypeFlags(NeonTypeFlags::Float32, false, Quad),
1272 HasFastHalfType);
1273 return Usgn ? Builder.CreateUIToFP(V: Ops[0], DestTy: Ty, Name: "vcvt")
1274 : Builder.CreateSIToFP(V: Ops[0], DestTy: Ty, Name: "vcvt");
1275 case NEON::BI__builtin_neon_vcvt_f16_s16:
1276 case NEON::BI__builtin_neon_vcvt_f16_u16:
1277 case NEON::BI__builtin_neon_vcvtq_f16_s16:
1278 case NEON::BI__builtin_neon_vcvtq_f16_u16:
1279 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
1280 Ty = GetNeonType(CGF: this, TypeFlags: NeonTypeFlags(NeonTypeFlags::Float16, false, Quad),
1281 HasFastHalfType);
1282 return Usgn ? Builder.CreateUIToFP(V: Ops[0], DestTy: Ty, Name: "vcvt")
1283 : Builder.CreateSIToFP(V: Ops[0], DestTy: Ty, Name: "vcvt");
1284 case NEON::BI__builtin_neon_vcvt_n_f16_s16:
1285 case NEON::BI__builtin_neon_vcvt_n_f16_u16:
1286 case NEON::BI__builtin_neon_vcvtq_n_f16_s16:
1287 case NEON::BI__builtin_neon_vcvtq_n_f16_u16: {
1288 llvm::Type *Tys[2] = { GetFloatNeonType(CGF: this, IntTypeFlags: Type), Ty };
1289 Function *F = CGM.getIntrinsic(IID: Int, Tys);
1290 return EmitNeonCall(F, Ops, name: "vcvt_n");
1291 }
1292 case NEON::BI__builtin_neon_vcvt_n_f32_v:
1293 case NEON::BI__builtin_neon_vcvt_n_f64_v:
1294 case NEON::BI__builtin_neon_vcvtq_n_f32_v:
1295 case NEON::BI__builtin_neon_vcvtq_n_f64_v: {
1296 llvm::Type *Tys[2] = { GetFloatNeonType(CGF: this, IntTypeFlags: Type), Ty };
1297 Int = Usgn ? LLVMIntrinsic : AltLLVMIntrinsic;
1298 Function *F = CGM.getIntrinsic(IID: Int, Tys);
1299 return EmitNeonCall(F, Ops, name: "vcvt_n");
1300 }
1301 case NEON::BI__builtin_neon_vcvt_n_s16_f16:
1302 case NEON::BI__builtin_neon_vcvt_n_s32_v:
1303 case NEON::BI__builtin_neon_vcvt_n_u16_f16:
1304 case NEON::BI__builtin_neon_vcvt_n_u32_v:
1305 case NEON::BI__builtin_neon_vcvt_n_s64_v:
1306 case NEON::BI__builtin_neon_vcvt_n_u64_v:
1307 case NEON::BI__builtin_neon_vcvtq_n_s16_f16:
1308 case NEON::BI__builtin_neon_vcvtq_n_s32_v:
1309 case NEON::BI__builtin_neon_vcvtq_n_u16_f16:
1310 case NEON::BI__builtin_neon_vcvtq_n_u32_v:
1311 case NEON::BI__builtin_neon_vcvtq_n_s64_v:
1312 case NEON::BI__builtin_neon_vcvtq_n_u64_v: {
1313 llvm::Type *Tys[2] = { Ty, GetFloatNeonType(CGF: this, IntTypeFlags: Type) };
1314 Function *F = CGM.getIntrinsic(IID: LLVMIntrinsic, Tys);
1315 return EmitNeonCall(F, Ops, name: "vcvt_n");
1316 }
1317 case NEON::BI__builtin_neon_vcvt_s32_v:
1318 case NEON::BI__builtin_neon_vcvt_u32_v:
1319 case NEON::BI__builtin_neon_vcvt_s64_v:
1320 case NEON::BI__builtin_neon_vcvt_u64_v:
1321 case NEON::BI__builtin_neon_vcvt_s16_f16:
1322 case NEON::BI__builtin_neon_vcvt_u16_f16:
1323 case NEON::BI__builtin_neon_vcvtq_s32_v:
1324 case NEON::BI__builtin_neon_vcvtq_u32_v:
1325 case NEON::BI__builtin_neon_vcvtq_s64_v:
1326 case NEON::BI__builtin_neon_vcvtq_u64_v:
1327 case NEON::BI__builtin_neon_vcvtq_s16_f16:
1328 case NEON::BI__builtin_neon_vcvtq_u16_f16: {
1329 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: GetFloatNeonType(CGF: this, IntTypeFlags: Type));
1330 if (Int) {
1331 // AArch64: use fptosi.sat/fptoui.sat unless under strict FP.
1332 if (!Builder.getIsFPConstrained())
1333 Int = Usgn ? Intrinsic::fptoui_sat : Intrinsic::fptosi_sat;
1334 llvm::Type *Tys[2] = {Ty, Ops[0]->getType()};
1335 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vcvtz");
1336 }
1337 // FIXME: ARM uses plain fptoui/fptosi which have UB on out-of-range
1338 // values. These should also use saturating intrinsics.
1339 return Usgn ? Builder.CreateFPToUI(V: Ops[0], DestTy: Ty, Name: "vcvt")
1340 : Builder.CreateFPToSI(V: Ops[0], DestTy: Ty, Name: "vcvt");
1341 }
1342 case NEON::BI__builtin_neon_vcvta_s16_f16:
1343 case NEON::BI__builtin_neon_vcvta_s32_v:
1344 case NEON::BI__builtin_neon_vcvta_s64_v:
1345 case NEON::BI__builtin_neon_vcvta_u16_f16:
1346 case NEON::BI__builtin_neon_vcvta_u32_v:
1347 case NEON::BI__builtin_neon_vcvta_u64_v:
1348 case NEON::BI__builtin_neon_vcvtaq_s16_f16:
1349 case NEON::BI__builtin_neon_vcvtaq_s32_v:
1350 case NEON::BI__builtin_neon_vcvtaq_s64_v:
1351 case NEON::BI__builtin_neon_vcvtaq_u16_f16:
1352 case NEON::BI__builtin_neon_vcvtaq_u32_v:
1353 case NEON::BI__builtin_neon_vcvtaq_u64_v:
1354 case NEON::BI__builtin_neon_vcvtn_s16_f16:
1355 case NEON::BI__builtin_neon_vcvtn_s32_v:
1356 case NEON::BI__builtin_neon_vcvtn_s64_v:
1357 case NEON::BI__builtin_neon_vcvtn_u16_f16:
1358 case NEON::BI__builtin_neon_vcvtn_u32_v:
1359 case NEON::BI__builtin_neon_vcvtn_u64_v:
1360 case NEON::BI__builtin_neon_vcvtnq_s16_f16:
1361 case NEON::BI__builtin_neon_vcvtnq_s32_v:
1362 case NEON::BI__builtin_neon_vcvtnq_s64_v:
1363 case NEON::BI__builtin_neon_vcvtnq_u16_f16:
1364 case NEON::BI__builtin_neon_vcvtnq_u32_v:
1365 case NEON::BI__builtin_neon_vcvtnq_u64_v:
1366 case NEON::BI__builtin_neon_vcvtp_s16_f16:
1367 case NEON::BI__builtin_neon_vcvtp_s32_v:
1368 case NEON::BI__builtin_neon_vcvtp_s64_v:
1369 case NEON::BI__builtin_neon_vcvtp_u16_f16:
1370 case NEON::BI__builtin_neon_vcvtp_u32_v:
1371 case NEON::BI__builtin_neon_vcvtp_u64_v:
1372 case NEON::BI__builtin_neon_vcvtpq_s16_f16:
1373 case NEON::BI__builtin_neon_vcvtpq_s32_v:
1374 case NEON::BI__builtin_neon_vcvtpq_s64_v:
1375 case NEON::BI__builtin_neon_vcvtpq_u16_f16:
1376 case NEON::BI__builtin_neon_vcvtpq_u32_v:
1377 case NEON::BI__builtin_neon_vcvtpq_u64_v:
1378 case NEON::BI__builtin_neon_vcvtm_s16_f16:
1379 case NEON::BI__builtin_neon_vcvtm_s32_v:
1380 case NEON::BI__builtin_neon_vcvtm_s64_v:
1381 case NEON::BI__builtin_neon_vcvtm_u16_f16:
1382 case NEON::BI__builtin_neon_vcvtm_u32_v:
1383 case NEON::BI__builtin_neon_vcvtm_u64_v:
1384 case NEON::BI__builtin_neon_vcvtmq_s16_f16:
1385 case NEON::BI__builtin_neon_vcvtmq_s32_v:
1386 case NEON::BI__builtin_neon_vcvtmq_s64_v:
1387 case NEON::BI__builtin_neon_vcvtmq_u16_f16:
1388 case NEON::BI__builtin_neon_vcvtmq_u32_v:
1389 case NEON::BI__builtin_neon_vcvtmq_u64_v: {
1390 llvm::Type *Tys[2] = { Ty, GetFloatNeonType(CGF: this, IntTypeFlags: Type) };
1391 return EmitNeonCall(F: CGM.getIntrinsic(IID: LLVMIntrinsic, Tys), Ops, name: NameHint);
1392 }
1393 case NEON::BI__builtin_neon_vcvtx_f32_v: {
1394 llvm::Type *Tys[2] = { VTy->getTruncatedElementVectorType(VTy), Ty};
1395 return EmitNeonCall(F: CGM.getIntrinsic(IID: LLVMIntrinsic, Tys), Ops, name: NameHint);
1396
1397 }
1398 case NEON::BI__builtin_neon_vext_v:
1399 case NEON::BI__builtin_neon_vextq_v: {
1400 int CV = cast<ConstantInt>(Val: Ops[2])->getSExtValue();
1401 SmallVector<int, 16> Indices;
1402 for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
1403 Indices.push_back(Elt: i+CV);
1404
1405 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
1406 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
1407 return Builder.CreateShuffleVector(V1: Ops[0], V2: Ops[1], Mask: Indices, Name: "vext");
1408 }
1409 case NEON::BI__builtin_neon_vfma_v:
1410 case NEON::BI__builtin_neon_vfmaq_v: {
1411 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
1412 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
1413 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: Ty);
1414
1415 // NEON intrinsic puts accumulator first, unlike the LLVM fma.
1416 return emitCallMaybeConstrainedFPBuiltin(
1417 CGF&: *this, IntrinsicID: Intrinsic::fma, ConstrainedIntrinsicID: Intrinsic::experimental_constrained_fma, Ty,
1418 Args: {Ops[1], Ops[2], Ops[0]});
1419 }
1420 case NEON::BI__builtin_neon_vld1_x2_v:
1421 case NEON::BI__builtin_neon_vld1q_x2_v:
1422 case NEON::BI__builtin_neon_vld1_x3_v:
1423 case NEON::BI__builtin_neon_vld1q_x3_v:
1424 case NEON::BI__builtin_neon_vld1_x4_v:
1425 case NEON::BI__builtin_neon_vld1q_x4_v: {
1426 llvm::Type *Tys[2] = {VTy, DefaultPtrTy};
1427 Function *F = CGM.getIntrinsic(IID: LLVMIntrinsic, Tys);
1428 Ops[1] = Builder.CreateCall(Callee: F, Args: Ops[1], Name: "vld1xN");
1429 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
1430 }
1431 case NEON::BI__builtin_neon_vld1_v:
1432 case NEON::BI__builtin_neon_vld1q_v: {
1433 llvm::Type *Tys[] = {Ty, Int8PtrTy};
1434 Ops.push_back(Elt: getAlignmentValue32(PtrOp0));
1435 return EmitNeonCall(F: CGM.getIntrinsic(IID: LLVMIntrinsic, Tys), Ops, name: "vld1");
1436 }
1437 case NEON::BI__builtin_neon_vld2_v:
1438 case NEON::BI__builtin_neon_vld2q_v:
1439 case NEON::BI__builtin_neon_vld3_v:
1440 case NEON::BI__builtin_neon_vld3q_v:
1441 case NEON::BI__builtin_neon_vld4_v:
1442 case NEON::BI__builtin_neon_vld4q_v:
1443 case NEON::BI__builtin_neon_vld2_dup_v:
1444 case NEON::BI__builtin_neon_vld2q_dup_v:
1445 case NEON::BI__builtin_neon_vld3_dup_v:
1446 case NEON::BI__builtin_neon_vld3q_dup_v:
1447 case NEON::BI__builtin_neon_vld4_dup_v:
1448 case NEON::BI__builtin_neon_vld4q_dup_v: {
1449 llvm::Type *Tys[] = {Ty, Int8PtrTy};
1450 Function *F = CGM.getIntrinsic(IID: LLVMIntrinsic, Tys);
1451 Value *Align = getAlignmentValue32(PtrOp1);
1452 Ops[1] = Builder.CreateCall(Callee: F, Args: {Ops[1], Align}, Name: NameHint);
1453 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
1454 }
1455 case NEON::BI__builtin_neon_vld1_dup_v:
1456 case NEON::BI__builtin_neon_vld1q_dup_v: {
1457 Value *V = PoisonValue::get(T: Ty);
1458 PtrOp0 = PtrOp0.withElementType(ElemTy: VTy->getElementType());
1459 LoadInst *Ld = Builder.CreateLoad(Addr: PtrOp0);
1460 llvm::Constant *CI = ConstantInt::get(Ty: SizeTy, V: 0);
1461 Ops[0] = Builder.CreateInsertElement(Vec: V, NewElt: Ld, Idx: CI);
1462 return EmitNeonSplat(V: Ops[0], C: CI);
1463 }
1464 case NEON::BI__builtin_neon_vld2_lane_v:
1465 case NEON::BI__builtin_neon_vld2q_lane_v:
1466 case NEON::BI__builtin_neon_vld3_lane_v:
1467 case NEON::BI__builtin_neon_vld3q_lane_v:
1468 case NEON::BI__builtin_neon_vld4_lane_v:
1469 case NEON::BI__builtin_neon_vld4q_lane_v: {
1470 llvm::Type *Tys[] = {Ty, Int8PtrTy};
1471 Function *F = CGM.getIntrinsic(IID: LLVMIntrinsic, Tys);
1472 for (unsigned I = 2; I < Ops.size() - 1; ++I)
1473 Ops[I] = Builder.CreateBitCast(V: Ops[I], DestTy: Ty);
1474 Ops.push_back(Elt: getAlignmentValue32(PtrOp1));
1475 Ops[1] = Builder.CreateCall(Callee: F, Args: ArrayRef(Ops).slice(N: 1), Name: NameHint);
1476 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
1477 }
1478 case NEON::BI__builtin_neon_vmovl_v: {
1479 llvm::FixedVectorType *DTy =
1480 llvm::FixedVectorType::getTruncatedElementVectorType(VTy);
1481 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: DTy);
1482 if (Usgn)
1483 return Builder.CreateZExt(V: Ops[0], DestTy: Ty, Name: "vmovl");
1484 return Builder.CreateSExt(V: Ops[0], DestTy: Ty, Name: "vmovl");
1485 }
1486 case NEON::BI__builtin_neon_vmovn_v: {
1487 llvm::FixedVectorType *QTy =
1488 llvm::FixedVectorType::getExtendedElementVectorType(VTy);
1489 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: QTy);
1490 return Builder.CreateTrunc(V: Ops[0], DestTy: Ty, Name: "vmovn");
1491 }
1492 case NEON::BI__builtin_neon_vmull_v:
1493 // FIXME: the integer vmull operations could be emitted in terms of pure
1494 // LLVM IR (2 exts followed by a mul). Unfortunately LLVM has a habit of
1495 // hoisting the exts outside loops. Until global ISel comes along that can
1496 // see through such movement this leads to bad CodeGen. So we need an
1497 // intrinsic for now.
1498 Int = Usgn ? Intrinsic::arm_neon_vmullu : Intrinsic::arm_neon_vmulls;
1499 Int = Type.isPoly() ? (unsigned)Intrinsic::arm_neon_vmullp : Int;
1500 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vmull");
1501 case NEON::BI__builtin_neon_vpadal_v:
1502 case NEON::BI__builtin_neon_vpadalq_v: {
1503 // The source operand type has twice as many elements of half the size.
1504 unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
1505 llvm::Type *EltTy =
1506 llvm::IntegerType::get(C&: getLLVMContext(), NumBits: EltBits / 2);
1507 auto *NarrowTy =
1508 llvm::FixedVectorType::get(ElementType: EltTy, NumElts: VTy->getNumElements() * 2);
1509 llvm::Type *Tys[2] = { Ty, NarrowTy };
1510 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: NameHint);
1511 }
1512 case NEON::BI__builtin_neon_vpaddl_v:
1513 case NEON::BI__builtin_neon_vpaddlq_v: {
1514 // The source operand type has twice as many elements of half the size.
1515 unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
1516 llvm::Type *EltTy = llvm::IntegerType::get(C&: getLLVMContext(), NumBits: EltBits / 2);
1517 auto *NarrowTy =
1518 llvm::FixedVectorType::get(ElementType: EltTy, NumElts: VTy->getNumElements() * 2);
1519 llvm::Type *Tys[2] = { Ty, NarrowTy };
1520 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vpaddl");
1521 }
1522 case NEON::BI__builtin_neon_vqdmlal_v:
1523 case NEON::BI__builtin_neon_vqdmlsl_v: {
1524 SmallVector<Value *, 2> MulOps(Ops.begin() + 1, Ops.end());
1525 Ops[1] =
1526 EmitNeonCall(F: CGM.getIntrinsic(IID: LLVMIntrinsic, Tys: Ty), Ops&: MulOps, name: "vqdmlal");
1527 Ops.resize(N: 2);
1528 return EmitNeonCall(F: CGM.getIntrinsic(IID: AltLLVMIntrinsic, Tys: Ty), Ops, name: NameHint);
1529 }
1530 case NEON::BI__builtin_neon_vqdmulhq_lane_v:
1531 case NEON::BI__builtin_neon_vqdmulh_lane_v:
1532 case NEON::BI__builtin_neon_vqrdmulhq_lane_v:
1533 case NEON::BI__builtin_neon_vqrdmulh_lane_v: {
1534 auto *RTy = cast<llvm::FixedVectorType>(Val: Ty);
1535 if (BuiltinID == NEON::BI__builtin_neon_vqdmulhq_lane_v ||
1536 BuiltinID == NEON::BI__builtin_neon_vqrdmulhq_lane_v)
1537 RTy = llvm::FixedVectorType::get(ElementType: RTy->getElementType(),
1538 NumElts: RTy->getNumElements() * 2);
1539 llvm::Type *Tys[2] = {
1540 RTy, GetNeonType(CGF: this, TypeFlags: NeonTypeFlags(Type.getEltType(), false,
1541 /*isQuad*/ false))};
1542 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: NameHint);
1543 }
1544 case NEON::BI__builtin_neon_vqdmulhq_laneq_v:
1545 case NEON::BI__builtin_neon_vqdmulh_laneq_v:
1546 case NEON::BI__builtin_neon_vqrdmulhq_laneq_v:
1547 case NEON::BI__builtin_neon_vqrdmulh_laneq_v: {
1548 llvm::Type *Tys[2] = {
1549 Ty, GetNeonType(CGF: this, TypeFlags: NeonTypeFlags(Type.getEltType(), false,
1550 /*isQuad*/ true))};
1551 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: NameHint);
1552 }
1553 case NEON::BI__builtin_neon_vqshl_n_v:
1554 case NEON::BI__builtin_neon_vqshlq_n_v:
1555 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vqshl_n",
1556 shift: 1, rightshift: false);
1557 case NEON::BI__builtin_neon_vqshlu_n_v:
1558 case NEON::BI__builtin_neon_vqshluq_n_v:
1559 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vqshlu_n",
1560 shift: 1, rightshift: false);
1561 case NEON::BI__builtin_neon_vrecpe_v:
1562 case NEON::BI__builtin_neon_vrecpeq_v:
1563 case NEON::BI__builtin_neon_vrsqrte_v:
1564 case NEON::BI__builtin_neon_vrsqrteq_v:
1565 Int = Ty->isFPOrFPVectorTy() ? LLVMIntrinsic : AltLLVMIntrinsic;
1566 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: NameHint);
1567 case NEON::BI__builtin_neon_vrndi_v:
1568 case NEON::BI__builtin_neon_vrndiq_v:
1569 Int = Builder.getIsFPConstrained()
1570 ? Intrinsic::experimental_constrained_nearbyint
1571 : Intrinsic::nearbyint;
1572 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: NameHint);
1573 case NEON::BI__builtin_neon_vrshr_n_v:
1574 case NEON::BI__builtin_neon_vrshrq_n_v:
1575 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vrshr_n",
1576 shift: 1, rightshift: true);
1577 case NEON::BI__builtin_neon_vsha512hq_u64:
1578 case NEON::BI__builtin_neon_vsha512h2q_u64:
1579 case NEON::BI__builtin_neon_vsha512su0q_u64:
1580 case NEON::BI__builtin_neon_vsha512su1q_u64: {
1581 Function *F = CGM.getIntrinsic(IID: Int);
1582 return EmitNeonCall(F, Ops, name: "");
1583 }
1584 case NEON::BI__builtin_neon_vshl_n_v:
1585 case NEON::BI__builtin_neon_vshlq_n_v:
1586 Ops[1] = EmitNeonShiftVector(V: Ops[1], Ty, neg: false);
1587 return Builder.CreateShl(LHS: Builder.CreateBitCast(V: Ops[0],DestTy: Ty), RHS: Ops[1],
1588 Name: "vshl_n");
1589 case NEON::BI__builtin_neon_vshll_n_v: {
1590 llvm::FixedVectorType *SrcTy =
1591 llvm::FixedVectorType::getTruncatedElementVectorType(VTy);
1592 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: SrcTy);
1593 if (Usgn)
1594 Ops[0] = Builder.CreateZExt(V: Ops[0], DestTy: VTy);
1595 else
1596 Ops[0] = Builder.CreateSExt(V: Ops[0], DestTy: VTy);
1597 Ops[1] = EmitNeonShiftVector(V: Ops[1], Ty: VTy, neg: false);
1598 return Builder.CreateShl(LHS: Ops[0], RHS: Ops[1], Name: "vshll_n");
1599 }
1600 case NEON::BI__builtin_neon_vshrn_n_v: {
1601 llvm::FixedVectorType *SrcTy =
1602 llvm::FixedVectorType::getExtendedElementVectorType(VTy);
1603 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: SrcTy);
1604 Ops[1] = EmitNeonShiftVector(V: Ops[1], Ty: SrcTy, neg: false);
1605 if (Usgn)
1606 Ops[0] = Builder.CreateLShr(LHS: Ops[0], RHS: Ops[1]);
1607 else
1608 Ops[0] = Builder.CreateAShr(LHS: Ops[0], RHS: Ops[1]);
1609 return Builder.CreateTrunc(V: Ops[0], DestTy: Ty, Name: "vshrn_n");
1610 }
1611 case NEON::BI__builtin_neon_vshr_n_v:
1612 case NEON::BI__builtin_neon_vshrq_n_v:
1613 return EmitNeonRShiftImm(Vec: Ops[0], Shift: Ops[1], Ty, usgn: Usgn, name: "vshr_n");
1614 case NEON::BI__builtin_neon_vst1_v:
1615 case NEON::BI__builtin_neon_vst1q_v:
1616 case NEON::BI__builtin_neon_vst2_v:
1617 case NEON::BI__builtin_neon_vst2q_v:
1618 case NEON::BI__builtin_neon_vst3_v:
1619 case NEON::BI__builtin_neon_vst3q_v:
1620 case NEON::BI__builtin_neon_vst4_v:
1621 case NEON::BI__builtin_neon_vst4q_v:
1622 case NEON::BI__builtin_neon_vst2_lane_v:
1623 case NEON::BI__builtin_neon_vst2q_lane_v:
1624 case NEON::BI__builtin_neon_vst3_lane_v:
1625 case NEON::BI__builtin_neon_vst3q_lane_v:
1626 case NEON::BI__builtin_neon_vst4_lane_v:
1627 case NEON::BI__builtin_neon_vst4q_lane_v: {
1628 llvm::Type *Tys[] = {Int8PtrTy, Ty};
1629 Ops.push_back(Elt: getAlignmentValue32(PtrOp0));
1630 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "");
1631 }
1632 case NEON::BI__builtin_neon_vsm3partw1q_u32:
1633 case NEON::BI__builtin_neon_vsm3partw2q_u32:
1634 case NEON::BI__builtin_neon_vsm3ss1q_u32:
1635 case NEON::BI__builtin_neon_vsm4ekeyq_u32:
1636 case NEON::BI__builtin_neon_vsm4eq_u32: {
1637 Function *F = CGM.getIntrinsic(IID: Int);
1638 return EmitNeonCall(F, Ops, name: "");
1639 }
1640 case NEON::BI__builtin_neon_vsm3tt1aq_u32:
1641 case NEON::BI__builtin_neon_vsm3tt1bq_u32:
1642 case NEON::BI__builtin_neon_vsm3tt2aq_u32:
1643 case NEON::BI__builtin_neon_vsm3tt2bq_u32: {
1644 Function *F = CGM.getIntrinsic(IID: Int);
1645 Ops[3] = Builder.CreateZExt(V: Ops[3], DestTy: Int64Ty);
1646 return EmitNeonCall(F, Ops, name: "");
1647 }
1648 case NEON::BI__builtin_neon_vst1_x2_v:
1649 case NEON::BI__builtin_neon_vst1q_x2_v:
1650 case NEON::BI__builtin_neon_vst1_x3_v:
1651 case NEON::BI__builtin_neon_vst1q_x3_v:
1652 case NEON::BI__builtin_neon_vst1_x4_v:
1653 case NEON::BI__builtin_neon_vst1q_x4_v: {
1654 // TODO: Currently in AArch32 mode the pointer operand comes first, whereas
1655 // in AArch64 it comes last. We may want to stick to one or another.
1656 if (Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_be ||
1657 Arch == llvm::Triple::aarch64_32) {
1658 llvm::Type *Tys[2] = {VTy, DefaultPtrTy};
1659 std::rotate(first: Ops.begin(), middle: Ops.begin() + 1, last: Ops.end());
1660 return EmitNeonCall(F: CGM.getIntrinsic(IID: LLVMIntrinsic, Tys), Ops, name: "");
1661 }
1662 llvm::Type *Tys[2] = {DefaultPtrTy, VTy};
1663 return EmitNeonCall(F: CGM.getIntrinsic(IID: LLVMIntrinsic, Tys), Ops, name: "");
1664 }
1665 case NEON::BI__builtin_neon_vsubhn_v: {
1666 llvm::FixedVectorType *SrcTy =
1667 llvm::FixedVectorType::getExtendedElementVectorType(VTy);
1668
1669 // %sum = add <4 x i32> %lhs, %rhs
1670 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: SrcTy);
1671 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: SrcTy);
1672 Ops[0] = Builder.CreateSub(LHS: Ops[0], RHS: Ops[1], Name: "vsubhn");
1673
1674 // %high = lshr <4 x i32> %sum, <i32 16, i32 16, i32 16, i32 16>
1675 Constant *ShiftAmt =
1676 ConstantInt::get(Ty: SrcTy, V: SrcTy->getScalarSizeInBits() / 2);
1677 Ops[0] = Builder.CreateLShr(LHS: Ops[0], RHS: ShiftAmt, Name: "vsubhn");
1678
1679 // %res = trunc <4 x i32> %high to <4 x i16>
1680 return Builder.CreateTrunc(V: Ops[0], DestTy: VTy, Name: "vsubhn");
1681 }
1682 case NEON::BI__builtin_neon_vtrn_v:
1683 case NEON::BI__builtin_neon_vtrnq_v: {
1684 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
1685 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: Ty);
1686 Value *SV = nullptr;
1687
1688 for (unsigned vi = 0; vi != 2; ++vi) {
1689 SmallVector<int, 16> Indices;
1690 for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
1691 Indices.push_back(Elt: i+vi);
1692 Indices.push_back(Elt: i+e+vi);
1693 }
1694 Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ptr: Ops[0], Idx0: vi);
1695 SV = Builder.CreateShuffleVector(V1: Ops[1], V2: Ops[2], Mask: Indices, Name: "vtrn");
1696 SV = Builder.CreateDefaultAlignedStore(Val: SV, Addr);
1697 }
1698 return SV;
1699 }
1700 case NEON::BI__builtin_neon_vtst_v:
1701 case NEON::BI__builtin_neon_vtstq_v: {
1702 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
1703 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
1704 Ops[0] = Builder.CreateAnd(LHS: Ops[0], RHS: Ops[1]);
1705 Ops[0] = Builder.CreateICmp(P: ICmpInst::ICMP_NE, LHS: Ops[0],
1706 RHS: ConstantAggregateZero::get(Ty));
1707 return Builder.CreateSExt(V: Ops[0], DestTy: Ty, Name: "vtst");
1708 }
1709 case NEON::BI__builtin_neon_vuzp_v:
1710 case NEON::BI__builtin_neon_vuzpq_v: {
1711 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
1712 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: Ty);
1713 Value *SV = nullptr;
1714
1715 for (unsigned vi = 0; vi != 2; ++vi) {
1716 SmallVector<int, 16> Indices;
1717 for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
1718 Indices.push_back(Elt: 2*i+vi);
1719
1720 Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ptr: Ops[0], Idx0: vi);
1721 SV = Builder.CreateShuffleVector(V1: Ops[1], V2: Ops[2], Mask: Indices, Name: "vuzp");
1722 SV = Builder.CreateDefaultAlignedStore(Val: SV, Addr);
1723 }
1724 return SV;
1725 }
1726 case NEON::BI__builtin_neon_vxarq_u64: {
1727 Function *F = CGM.getIntrinsic(IID: Int);
1728 Ops[2] = Builder.CreateZExt(V: Ops[2], DestTy: Int64Ty);
1729 return EmitNeonCall(F, Ops, name: "");
1730 }
1731 case NEON::BI__builtin_neon_vzip_v:
1732 case NEON::BI__builtin_neon_vzipq_v: {
1733 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
1734 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: Ty);
1735 Value *SV = nullptr;
1736
1737 for (unsigned vi = 0; vi != 2; ++vi) {
1738 SmallVector<int, 16> Indices;
1739 for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
1740 Indices.push_back(Elt: (i + vi*e) >> 1);
1741 Indices.push_back(Elt: ((i + vi*e) >> 1)+e);
1742 }
1743 Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ptr: Ops[0], Idx0: vi);
1744 SV = Builder.CreateShuffleVector(V1: Ops[1], V2: Ops[2], Mask: Indices, Name: "vzip");
1745 SV = Builder.CreateDefaultAlignedStore(Val: SV, Addr);
1746 }
1747 return SV;
1748 }
1749 case NEON::BI__builtin_neon_vdot_s32:
1750 case NEON::BI__builtin_neon_vdot_u32:
1751 case NEON::BI__builtin_neon_vdotq_s32:
1752 case NEON::BI__builtin_neon_vdotq_u32: {
1753 auto *InputTy =
1754 llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: Ty->getPrimitiveSizeInBits() / 8);
1755 llvm::Type *Tys[2] = { Ty, InputTy };
1756 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vdot");
1757 }
1758 case NEON::BI__builtin_neon_vfmlal_low_f16:
1759 case NEON::BI__builtin_neon_vfmlalq_low_f16: {
1760 auto *InputTy =
1761 llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: Ty->getPrimitiveSizeInBits() / 16);
1762 llvm::Type *Tys[2] = { Ty, InputTy };
1763 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vfmlal_low");
1764 }
1765 case NEON::BI__builtin_neon_vfmlsl_low_f16:
1766 case NEON::BI__builtin_neon_vfmlslq_low_f16: {
1767 auto *InputTy =
1768 llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: Ty->getPrimitiveSizeInBits() / 16);
1769 llvm::Type *Tys[2] = { Ty, InputTy };
1770 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vfmlsl_low");
1771 }
1772 case NEON::BI__builtin_neon_vfmlal_high_f16:
1773 case NEON::BI__builtin_neon_vfmlalq_high_f16: {
1774 auto *InputTy =
1775 llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: Ty->getPrimitiveSizeInBits() / 16);
1776 llvm::Type *Tys[2] = { Ty, InputTy };
1777 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vfmlal_high");
1778 }
1779 case NEON::BI__builtin_neon_vfmlsl_high_f16:
1780 case NEON::BI__builtin_neon_vfmlslq_high_f16: {
1781 auto *InputTy =
1782 llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: Ty->getPrimitiveSizeInBits() / 16);
1783 llvm::Type *Tys[2] = { Ty, InputTy };
1784 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vfmlsl_high");
1785 }
1786 case NEON::BI__builtin_neon_vmmlaq_s32:
1787 case NEON::BI__builtin_neon_vmmlaq_u32: {
1788 auto *InputTy =
1789 llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: Ty->getPrimitiveSizeInBits() / 8);
1790 llvm::Type *Tys[2] = { Ty, InputTy };
1791 return EmitNeonCall(F: CGM.getIntrinsic(IID: LLVMIntrinsic, Tys), Ops, name: "vmmla");
1792 }
1793 case NEON::BI__builtin_neon_vmmlaq_f16:
1794 case NEON::BI__builtin_neon_vmmlaq_f32_f16: {
1795 auto *InputTy =
1796 llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: Ty->getPrimitiveSizeInBits() / 16);
1797 llvm::Type *Tys[2] = {Ty, InputTy};
1798 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "fmmla");
1799 }
1800 case NEON::BI__builtin_neon_vusmmlaq_s32: {
1801 auto *InputTy =
1802 llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: Ty->getPrimitiveSizeInBits() / 8);
1803 llvm::Type *Tys[2] = { Ty, InputTy };
1804 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vusmmla");
1805 }
1806 case NEON::BI__builtin_neon_vusdot_s32:
1807 case NEON::BI__builtin_neon_vusdotq_s32: {
1808 auto *InputTy =
1809 llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: Ty->getPrimitiveSizeInBits() / 8);
1810 llvm::Type *Tys[2] = { Ty, InputTy };
1811 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vusdot");
1812 }
1813 case NEON::BI__builtin_neon_vbfdot_f32:
1814 case NEON::BI__builtin_neon_vbfdotq_f32: {
1815 llvm::Type *InputTy =
1816 llvm::FixedVectorType::get(ElementType: BFloatTy, NumElts: Ty->getPrimitiveSizeInBits() / 16);
1817 llvm::Type *Tys[2] = { Ty, InputTy };
1818 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vbfdot");
1819 }
1820 case NEON::BI__builtin_neon___a32_vcvt_bf16_f32: {
1821 llvm::Type *Tys[1] = { Ty };
1822 Function *F = CGM.getIntrinsic(IID: Int, Tys);
1823 return EmitNeonCall(F, Ops, name: "vcvtfp2bf");
1824 }
1825
1826 }
1827
1828 assert(Int && "Expected valid intrinsic number");
1829
1830 // Determine the type(s) of this overloaded AArch64 intrinsic.
1831 Function *F = LookupNeonLLVMIntrinsic(IntrinsicID: Int, Modifier, ArgType: Ty, E);
1832
1833 Value *Result = EmitNeonCall(F, Ops, name: NameHint);
1834 llvm::Type *ResultType = ConvertType(T: E->getType());
1835 // AArch64 intrinsic one-element vector type cast to
1836 // scalar type expected by the builtin
1837 return Builder.CreateBitCast(V: Result, DestTy: ResultType, Name: NameHint);
1838}
1839
1840Value *
1841CodeGenFunction::EmitAArch64CompareBuiltinExpr(Value *Op, llvm::Type *Ty,
1842 const CmpInst::Predicate Pred,
1843 const Twine &Name) {
1844
1845 if (isa<FixedVectorType>(Val: Ty)) {
1846 // Vector types are cast to i8 vectors. Recover original type.
1847 Op = Builder.CreateBitCast(V: Op, DestTy: Ty);
1848 }
1849
1850 Constant *zero = Constant::getNullValue(Ty: Op->getType());
1851
1852 if (CmpInst::isFPPredicate(P: Pred)) {
1853 if (Pred == CmpInst::FCMP_OEQ)
1854 Op = Builder.CreateFCmp(P: Pred, LHS: Op, RHS: zero);
1855 else
1856 Op = Builder.CreateFCmpS(P: Pred, LHS: Op, RHS: zero);
1857 } else {
1858 Op = Builder.CreateICmp(P: Pred, LHS: Op, RHS: zero);
1859 }
1860
1861 llvm::Type *ResTy = Ty;
1862 if (auto *VTy = dyn_cast<FixedVectorType>(Val: Ty))
1863 ResTy = FixedVectorType::get(
1864 ElementType: IntegerType::get(C&: getLLVMContext(), NumBits: VTy->getScalarSizeInBits()),
1865 NumElts: VTy->getNumElements());
1866
1867 return Builder.CreateSExt(V: Op, DestTy: ResTy, Name);
1868}
1869
1870static Value *packTBLDVectorList(CodeGenFunction &CGF, ArrayRef<Value *> Ops,
1871 Value *ExtOp, Value *IndexOp,
1872 llvm::Type *ResTy, unsigned IntID,
1873 const char *Name) {
1874 SmallVector<Value *, 2> TblOps;
1875 if (ExtOp)
1876 TblOps.push_back(Elt: ExtOp);
1877
1878 // Build a vector containing sequential number like (0, 1, 2, ..., 15)
1879 SmallVector<int, 16> Indices;
1880 auto *TblTy = cast<llvm::FixedVectorType>(Val: Ops[0]->getType());
1881 for (unsigned i = 0, e = TblTy->getNumElements(); i != e; ++i) {
1882 Indices.push_back(Elt: 2*i);
1883 Indices.push_back(Elt: 2*i+1);
1884 }
1885
1886 int PairPos = 0, End = Ops.size() - 1;
1887 while (PairPos < End) {
1888 TblOps.push_back(Elt: CGF.Builder.CreateShuffleVector(V1: Ops[PairPos],
1889 V2: Ops[PairPos+1], Mask: Indices,
1890 Name));
1891 PairPos += 2;
1892 }
1893
1894 // If there's an odd number of 64-bit lookup table, fill the high 64-bit
1895 // of the 128-bit lookup table with zero.
1896 if (PairPos == End) {
1897 Value *ZeroTbl = ConstantAggregateZero::get(Ty: TblTy);
1898 TblOps.push_back(Elt: CGF.Builder.CreateShuffleVector(V1: Ops[PairPos],
1899 V2: ZeroTbl, Mask: Indices, Name));
1900 }
1901
1902 Function *TblF;
1903 TblOps.push_back(Elt: IndexOp);
1904 TblF = CGF.CGM.getIntrinsic(IID: IntID, Tys: ResTy);
1905
1906 return CGF.EmitNeonCall(F: TblF, Ops&: TblOps, name: Name);
1907}
1908
1909Value *CodeGenFunction::GetValueForARMHint(unsigned BuiltinID) {
1910 unsigned Value;
1911 switch (BuiltinID) {
1912 default:
1913 return nullptr;
1914 case clang::ARM::BI__builtin_arm_nop:
1915 Value = 0;
1916 break;
1917 case clang::ARM::BI__builtin_arm_yield:
1918 case clang::ARM::BI__yield:
1919 Value = 1;
1920 break;
1921 case clang::ARM::BI__builtin_arm_wfe:
1922 case clang::ARM::BI__wfe:
1923 Value = 2;
1924 break;
1925 case clang::ARM::BI__builtin_arm_wfi:
1926 case clang::ARM::BI__wfi:
1927 Value = 3;
1928 break;
1929 case clang::ARM::BI__builtin_arm_sev:
1930 case clang::ARM::BI__sev:
1931 Value = 4;
1932 break;
1933 case clang::ARM::BI__builtin_arm_sevl:
1934 case clang::ARM::BI__sevl:
1935 Value = 5;
1936 break;
1937 }
1938
1939 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::arm_hint),
1940 Args: llvm::ConstantInt::get(Ty: Int32Ty, V: Value));
1941}
1942
1943enum SpecialRegisterAccessKind {
1944 NormalRead,
1945 VolatileRead,
1946 Write,
1947};
1948
1949// Generates the IR for the read/write special register builtin,
1950// ValueType is the type of the value that is to be written or read,
1951// RegisterType is the type of the register being written to or read from.
1952static Value *EmitSpecialRegisterBuiltin(CodeGenFunction &CGF,
1953 const CallExpr *E,
1954 llvm::Type *RegisterType,
1955 llvm::Type *ValueType,
1956 SpecialRegisterAccessKind AccessKind,
1957 StringRef SysReg = "") {
1958 // write and register intrinsics only support 32, 64 and 128 bit operations.
1959 assert((RegisterType->isIntegerTy(32) || RegisterType->isIntegerTy(64) ||
1960 RegisterType->isIntegerTy(128)) &&
1961 "Unsupported size for register.");
1962
1963 CodeGen::CGBuilderTy &Builder = CGF.Builder;
1964 CodeGen::CodeGenModule &CGM = CGF.CGM;
1965 LLVMContext &Context = CGM.getLLVMContext();
1966
1967 if (SysReg.empty()) {
1968 const Expr *SysRegStrExpr = E->getArg(Arg: 0)->IgnoreParenCasts();
1969 SysReg = cast<clang::StringLiteral>(Val: SysRegStrExpr)->getString();
1970 }
1971
1972 llvm::Metadata *Ops[] = { llvm::MDString::get(Context, Str: SysReg) };
1973 llvm::MDNode *RegName = llvm::MDNode::get(Context, MDs: Ops);
1974 llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, MD: RegName);
1975
1976 llvm::Type *Types[] = { RegisterType };
1977
1978 bool MixedTypes = RegisterType->isIntegerTy(BitWidth: 64) && ValueType->isIntegerTy(BitWidth: 32);
1979 assert(!(RegisterType->isIntegerTy(32) && ValueType->isIntegerTy(64))
1980 && "Can't fit 64-bit value in 32-bit register");
1981
1982 if (AccessKind != Write) {
1983 assert(AccessKind == NormalRead || AccessKind == VolatileRead);
1984 llvm::Function *F = CGM.getIntrinsic(
1985 IID: AccessKind == VolatileRead ? Intrinsic::read_volatile_register
1986 : Intrinsic::read_register,
1987 Tys: Types);
1988 llvm::Value *Call = Builder.CreateCall(Callee: F, Args: Metadata);
1989
1990 if (MixedTypes)
1991 // Read into 64 bit register and then truncate result to 32 bit.
1992 return Builder.CreateTrunc(V: Call, DestTy: ValueType);
1993
1994 if (ValueType->isPointerTy())
1995 // Have i32/i64 result (Call) but want to return a VoidPtrTy (i8*).
1996 return Builder.CreateIntToPtr(V: Call, DestTy: ValueType);
1997
1998 return Call;
1999 }
2000
2001 llvm::Function *F = CGM.getIntrinsic(IID: Intrinsic::write_register, Tys: Types);
2002 llvm::Value *ArgValue = CGF.EmitScalarExpr(E: E->getArg(Arg: 1));
2003 if (MixedTypes) {
2004 // Extend 32 bit write value to 64 bit to pass to write.
2005 ArgValue = Builder.CreateZExt(V: ArgValue, DestTy: RegisterType);
2006 return Builder.CreateCall(Callee: F, Args: { Metadata, ArgValue });
2007 }
2008
2009 if (ValueType->isPointerTy()) {
2010 // Have VoidPtrTy ArgValue but want to return an i32/i64.
2011 ArgValue = Builder.CreatePtrToInt(V: ArgValue, DestTy: RegisterType);
2012 return Builder.CreateCall(Callee: F, Args: { Metadata, ArgValue });
2013 }
2014
2015 return Builder.CreateCall(Callee: F, Args: { Metadata, ArgValue });
2016}
2017
2018static Value *EmitRangePrefetchBuiltin(CodeGenFunction &CGF, unsigned BuiltinID,
2019 const CallExpr *E) {
2020 CodeGen::CGBuilderTy &Builder = CGF.Builder;
2021 CodeGen::CodeGenModule &CGM = CGF.CGM;
2022 SmallVector<llvm::Value *, 4> Ops;
2023
2024 auto getIntArg = [&](unsigned ArgNo) {
2025 Expr::EvalResult Result;
2026 if (!E->getArg(Arg: ArgNo)->EvaluateAsInt(Result, Ctx: CGM.getContext()))
2027 llvm_unreachable("Expected constant argument to range prefetch.");
2028 return Result.Val.getInt().getExtValue();
2029 };
2030
2031 Ops.push_back(Elt: CGF.EmitScalarExpr(E: E->getArg(Arg: 0))); /*Addr*/
2032 Ops.push_back(Elt: CGF.EmitScalarExpr(E: E->getArg(Arg: 1))); /*Access Kind*/
2033 Ops.push_back(Elt: CGF.EmitScalarExpr(E: E->getArg(Arg: 2))); /*Policy*/
2034
2035 if (BuiltinID == clang::AArch64::BI__builtin_arm_range_prefetch_x) {
2036 auto Length = getIntArg(3);
2037 auto Count = getIntArg(4) - 1;
2038 auto Stride = getIntArg(5);
2039 auto Distance = getIntArg(6);
2040
2041 // Map ReuseDistance given in bytes to four bits representing decreasing
2042 // powers of two in the range 512MiB (0b0001) to 32KiB (0b1111). Values
2043 // are rounded up to the nearest power of 2, starting at 32KiB. Any value
2044 // over the maximum is represented by 0 (distance not known).
2045 if (Distance > 0) {
2046 Distance = llvm::Log2_32_Ceil(Value: Distance);
2047 if (Distance < 15)
2048 Distance = 15;
2049 else if (Distance > 29)
2050 Distance = 0;
2051 else
2052 Distance = 30 - Distance;
2053 }
2054
2055 uint64_t Mask22 = (1ULL << 22) - 1;
2056 uint64_t Mask16 = (1ULL << 16) - 1;
2057 uint64_t Metadata = (Distance << 60) | ((Stride & Mask22) << 38) |
2058 ((Count & Mask16) << 22) | (Length & Mask22);
2059
2060 Ops.push_back(Elt: llvm::ConstantInt::get(Ty: Builder.getInt64Ty(), V: Metadata));
2061 } else
2062 Ops.push_back(Elt: CGF.EmitScalarExpr(E: E->getArg(Arg: 3)));
2063
2064 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_range_prefetch),
2065 Args: Ops);
2066}
2067
2068/// Return true if BuiltinID is an overloaded Neon intrinsic with an extra
2069/// argument that specifies the vector type. The additional argument is meant
2070/// for Sema checking (see `CheckNeonBuiltinFunctionCall`) and this function
2071/// should be kept consistent with the logic in Sema.
2072/// TODO: Make this return false for SISD builtins.
2073static bool HasExtraNeonArgument(unsigned BuiltinID) {
2074 // Required by the headers included below, but not in this particular
2075 // function.
2076 [[maybe_unused]] int PtrArgNum = -1;
2077 [[maybe_unused]] bool HasConstPtr = false;
2078
2079 // The mask encodes the type. We don't care about the actual value. Instead,
2080 // we just check whether its been set.
2081 uint64_t mask = 0;
2082 switch (BuiltinID) {
2083#define GET_NEON_OVERLOAD_CHECK
2084#include "clang/Basic/arm_fp16.inc"
2085#include "clang/Basic/arm_neon.inc"
2086#undef GET_NEON_OVERLOAD_CHECK
2087 // Non-neon builtins for controling VFP that take extra argument for
2088 // discriminating the type.
2089 case ARM::BI__builtin_arm_vcvtr_f:
2090 case ARM::BI__builtin_arm_vcvtr_d:
2091 mask = 1;
2092 }
2093
2094 if (mask)
2095 return true;
2096
2097 return false;
2098}
2099
2100Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
2101 const CallExpr *E,
2102 ReturnValueSlot ReturnValue,
2103 llvm::Triple::ArchType Arch) {
2104 if (auto Hint = GetValueForARMHint(BuiltinID))
2105 return Hint;
2106
2107 if (BuiltinID == clang::ARM::BI__emit) {
2108 bool IsThumb = getTarget().getTriple().getArch() == llvm::Triple::thumb;
2109 llvm::FunctionType *FTy =
2110 llvm::FunctionType::get(Result: VoidTy, /*Variadic=*/isVarArg: false);
2111
2112 Expr::EvalResult Result;
2113 if (!E->getArg(Arg: 0)->EvaluateAsInt(Result, Ctx: CGM.getContext()))
2114 llvm_unreachable("Sema will ensure that the parameter is constant");
2115
2116 llvm::APSInt Value = Result.Val.getInt();
2117 uint64_t ZExtValue = Value.zextOrTrunc(width: IsThumb ? 16 : 32).getZExtValue();
2118
2119 llvm::InlineAsm *Emit =
2120 IsThumb ? InlineAsm::get(Ty: FTy, AsmString: ".inst.n 0x" + utohexstr(X: ZExtValue), Constraints: "",
2121 /*hasSideEffects=*/true)
2122 : InlineAsm::get(Ty: FTy, AsmString: ".inst 0x" + utohexstr(X: ZExtValue), Constraints: "",
2123 /*hasSideEffects=*/true);
2124
2125 return Builder.CreateCall(Callee: Emit);
2126 }
2127
2128 if (BuiltinID == clang::ARM::BI__builtin_arm_dbg) {
2129 Value *Option = EmitScalarExpr(E: E->getArg(Arg: 0));
2130 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::arm_dbg), Args: Option);
2131 }
2132
2133 if (BuiltinID == clang::ARM::BI__builtin_arm_prefetch) {
2134 Value *Address = EmitScalarExpr(E: E->getArg(Arg: 0));
2135 Value *RW = EmitScalarExpr(E: E->getArg(Arg: 1));
2136 Value *IsData = EmitScalarExpr(E: E->getArg(Arg: 2));
2137
2138 // Locality is not supported on ARM target
2139 Value *Locality = llvm::ConstantInt::get(Ty: Int32Ty, V: 3);
2140
2141 Function *F = CGM.getIntrinsic(IID: Intrinsic::prefetch, Tys: Address->getType());
2142 return Builder.CreateCall(Callee: F, Args: {Address, RW, Locality, IsData});
2143 }
2144
2145 if (BuiltinID == clang::ARM::BI__builtin_arm_rbit) {
2146 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
2147 return Builder.CreateCall(
2148 Callee: CGM.getIntrinsic(IID: Intrinsic::bitreverse, Tys: Arg->getType()), Args: Arg, Name: "rbit");
2149 }
2150
2151 if (BuiltinID == clang::ARM::BI__builtin_arm_clz ||
2152 BuiltinID == clang::ARM::BI__builtin_arm_clz64) {
2153 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
2154 Function *F = CGM.getIntrinsic(IID: Intrinsic::ctlz, Tys: Arg->getType());
2155 Value *Res = Builder.CreateCall(Callee: F, Args: {Arg, Builder.getInt1(V: false)});
2156 if (BuiltinID == clang::ARM::BI__builtin_arm_clz64)
2157 Res = Builder.CreateTrunc(V: Res, DestTy: Builder.getInt32Ty());
2158 return Res;
2159 }
2160
2161
2162 if (BuiltinID == clang::ARM::BI__builtin_arm_cls) {
2163 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
2164 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::arm_cls), Args: Arg, Name: "cls");
2165 }
2166 if (BuiltinID == clang::ARM::BI__builtin_arm_cls64) {
2167 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
2168 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::arm_cls64), Args: Arg,
2169 Name: "cls");
2170 }
2171
2172 if (BuiltinID == clang::ARM::BI__clear_cache) {
2173 Value *Begin = EmitScalarExpr(E: E->getArg(Arg: 0));
2174 Value *End = EmitScalarExpr(E: E->getArg(Arg: 1));
2175 Function *F = CGM.getIntrinsic(IID: Intrinsic::clear_cache, Tys: {CGM.DefaultPtrTy});
2176 return Builder.CreateCall(Callee: F, Args: {Begin, End});
2177 }
2178
2179 if (BuiltinID == clang::ARM::BI__builtin_arm_mcrr ||
2180 BuiltinID == clang::ARM::BI__builtin_arm_mcrr2) {
2181 Function *F;
2182
2183 switch (BuiltinID) {
2184 default: llvm_unreachable("unexpected builtin");
2185 case clang::ARM::BI__builtin_arm_mcrr:
2186 F = CGM.getIntrinsic(IID: Intrinsic::arm_mcrr);
2187 break;
2188 case clang::ARM::BI__builtin_arm_mcrr2:
2189 F = CGM.getIntrinsic(IID: Intrinsic::arm_mcrr2);
2190 break;
2191 }
2192
2193 // MCRR{2} instruction has 5 operands but
2194 // the intrinsic has 4 because Rt and Rt2
2195 // are represented as a single unsigned 64
2196 // bit integer in the intrinsic definition
2197 // but internally it's represented as 2 32
2198 // bit integers.
2199
2200 Value *Coproc = EmitScalarExpr(E: E->getArg(Arg: 0));
2201 Value *Opc1 = EmitScalarExpr(E: E->getArg(Arg: 1));
2202 Value *RtAndRt2 = EmitScalarExpr(E: E->getArg(Arg: 2));
2203 Value *CRm = EmitScalarExpr(E: E->getArg(Arg: 3));
2204
2205 Value *C1 = llvm::ConstantInt::get(Ty: Int64Ty, V: 32);
2206 Value *Rt = Builder.CreateTruncOrBitCast(V: RtAndRt2, DestTy: Int32Ty);
2207 Value *Rt2 = Builder.CreateLShr(LHS: RtAndRt2, RHS: C1);
2208 Rt2 = Builder.CreateTruncOrBitCast(V: Rt2, DestTy: Int32Ty);
2209
2210 return Builder.CreateCall(Callee: F, Args: {Coproc, Opc1, Rt, Rt2, CRm});
2211 }
2212
2213 if (BuiltinID == clang::ARM::BI__builtin_arm_mrrc ||
2214 BuiltinID == clang::ARM::BI__builtin_arm_mrrc2) {
2215 Function *F;
2216
2217 switch (BuiltinID) {
2218 default: llvm_unreachable("unexpected builtin");
2219 case clang::ARM::BI__builtin_arm_mrrc:
2220 F = CGM.getIntrinsic(IID: Intrinsic::arm_mrrc);
2221 break;
2222 case clang::ARM::BI__builtin_arm_mrrc2:
2223 F = CGM.getIntrinsic(IID: Intrinsic::arm_mrrc2);
2224 break;
2225 }
2226
2227 Value *Coproc = EmitScalarExpr(E: E->getArg(Arg: 0));
2228 Value *Opc1 = EmitScalarExpr(E: E->getArg(Arg: 1));
2229 Value *CRm = EmitScalarExpr(E: E->getArg(Arg: 2));
2230 Value *RtAndRt2 = Builder.CreateCall(Callee: F, Args: {Coproc, Opc1, CRm});
2231
2232 // Returns an unsigned 64 bit integer, represented
2233 // as two 32 bit integers.
2234
2235 Value *Rt = Builder.CreateExtractValue(Agg: RtAndRt2, Idxs: 1);
2236 Value *Rt1 = Builder.CreateExtractValue(Agg: RtAndRt2, Idxs: 0);
2237 Rt = Builder.CreateZExt(V: Rt, DestTy: Int64Ty);
2238 Rt1 = Builder.CreateZExt(V: Rt1, DestTy: Int64Ty);
2239
2240 Value *ShiftCast = llvm::ConstantInt::get(Ty: Int64Ty, V: 32);
2241 RtAndRt2 = Builder.CreateShl(LHS: Rt, RHS: ShiftCast, Name: "shl", HasNUW: true);
2242 RtAndRt2 = Builder.CreateOr(LHS: RtAndRt2, RHS: Rt1);
2243
2244 return Builder.CreateBitCast(V: RtAndRt2, DestTy: ConvertType(T: E->getType()));
2245 }
2246
2247 if (BuiltinID == clang::ARM::BI__builtin_arm_ldrexd ||
2248 ((BuiltinID == clang::ARM::BI__builtin_arm_ldrex ||
2249 BuiltinID == clang::ARM::BI__builtin_arm_ldaex) &&
2250 getContext().getTypeSize(T: E->getType()) == 64) ||
2251 BuiltinID == clang::ARM::BI__ldrexd) {
2252 Function *F;
2253
2254 switch (BuiltinID) {
2255 default: llvm_unreachable("unexpected builtin");
2256 case clang::ARM::BI__builtin_arm_ldaex:
2257 F = CGM.getIntrinsic(IID: Intrinsic::arm_ldaexd);
2258 break;
2259 case clang::ARM::BI__builtin_arm_ldrexd:
2260 case clang::ARM::BI__builtin_arm_ldrex:
2261 case clang::ARM::BI__ldrexd:
2262 F = CGM.getIntrinsic(IID: Intrinsic::arm_ldrexd);
2263 break;
2264 }
2265
2266 Value *LdPtr = EmitScalarExpr(E: E->getArg(Arg: 0));
2267 Value *Val = Builder.CreateCall(Callee: F, Args: LdPtr, Name: "ldrexd");
2268
2269 Value *Val0 = Builder.CreateExtractValue(Agg: Val, Idxs: 1);
2270 Value *Val1 = Builder.CreateExtractValue(Agg: Val, Idxs: 0);
2271 Val0 = Builder.CreateZExt(V: Val0, DestTy: Int64Ty);
2272 Val1 = Builder.CreateZExt(V: Val1, DestTy: Int64Ty);
2273
2274 Value *ShiftCst = llvm::ConstantInt::get(Ty: Int64Ty, V: 32);
2275 Val = Builder.CreateShl(LHS: Val0, RHS: ShiftCst, Name: "shl", HasNUW: true /* nuw */);
2276 Val = Builder.CreateOr(LHS: Val, RHS: Val1);
2277 return Builder.CreateBitCast(V: Val, DestTy: ConvertType(T: E->getType()));
2278 }
2279
2280 if (BuiltinID == clang::ARM::BI__builtin_arm_ldrex ||
2281 BuiltinID == clang::ARM::BI__builtin_arm_ldaex) {
2282 Value *LoadAddr = EmitScalarExpr(E: E->getArg(Arg: 0));
2283
2284 QualType Ty = E->getType();
2285 llvm::Type *RealResTy = ConvertType(T: Ty);
2286 llvm::Type *IntTy =
2287 llvm::IntegerType::get(C&: getLLVMContext(), NumBits: getContext().getTypeSize(T: Ty));
2288
2289 Function *F = CGM.getIntrinsic(
2290 IID: BuiltinID == clang::ARM::BI__builtin_arm_ldaex ? Intrinsic::arm_ldaex
2291 : Intrinsic::arm_ldrex,
2292 Tys: DefaultPtrTy);
2293 CallInst *Val = Builder.CreateCall(Callee: F, Args: LoadAddr, Name: "ldrex");
2294 Val->addParamAttr(
2295 ArgNo: 0, Attr: Attribute::get(Context&: getLLVMContext(), Kind: Attribute::ElementType, Ty: IntTy));
2296
2297 if (RealResTy->isPointerTy())
2298 return Builder.CreateIntToPtr(V: Val, DestTy: RealResTy);
2299 else {
2300 llvm::Type *IntResTy = llvm::IntegerType::get(
2301 C&: getLLVMContext(), NumBits: CGM.getDataLayout().getTypeSizeInBits(Ty: RealResTy));
2302 return Builder.CreateBitCast(V: Builder.CreateTruncOrBitCast(V: Val, DestTy: IntResTy),
2303 DestTy: RealResTy);
2304 }
2305 }
2306
2307 if (BuiltinID == clang::ARM::BI__builtin_arm_strexd ||
2308 ((BuiltinID == clang::ARM::BI__builtin_arm_stlex ||
2309 BuiltinID == clang::ARM::BI__builtin_arm_strex) &&
2310 getContext().getTypeSize(T: E->getArg(Arg: 0)->getType()) == 64)) {
2311 Function *F = CGM.getIntrinsic(
2312 IID: BuiltinID == clang::ARM::BI__builtin_arm_stlex ? Intrinsic::arm_stlexd
2313 : Intrinsic::arm_strexd);
2314 llvm::Type *STy = llvm::StructType::get(elt1: Int32Ty, elts: Int32Ty);
2315
2316 Address Tmp = CreateMemTempWithoutCast(T: E->getArg(Arg: 0)->getType());
2317 Value *Val = EmitScalarExpr(E: E->getArg(Arg: 0));
2318 Builder.CreateStore(Val, Addr: Tmp);
2319
2320 Address LdPtr = Tmp.withElementType(ElemTy: STy);
2321 Val = Builder.CreateLoad(Addr: LdPtr);
2322
2323 Value *Arg0 = Builder.CreateExtractValue(Agg: Val, Idxs: 0);
2324 Value *Arg1 = Builder.CreateExtractValue(Agg: Val, Idxs: 1);
2325 Value *StPtr = EmitScalarExpr(E: E->getArg(Arg: 1));
2326 return Builder.CreateCall(Callee: F, Args: {Arg0, Arg1, StPtr}, Name: "strexd");
2327 }
2328
2329 if (BuiltinID == clang::ARM::BI__builtin_arm_strex ||
2330 BuiltinID == clang::ARM::BI__builtin_arm_stlex) {
2331 Value *StoreVal = EmitScalarExpr(E: E->getArg(Arg: 0));
2332 Value *StoreAddr = EmitScalarExpr(E: E->getArg(Arg: 1));
2333
2334 QualType Ty = E->getArg(Arg: 0)->getType();
2335 llvm::Type *StoreTy =
2336 llvm::IntegerType::get(C&: getLLVMContext(), NumBits: getContext().getTypeSize(T: Ty));
2337
2338 if (StoreVal->getType()->isPointerTy())
2339 StoreVal = Builder.CreatePtrToInt(V: StoreVal, DestTy: Int32Ty);
2340 else {
2341 llvm::Type *IntTy = llvm::IntegerType::get(
2342 C&: getLLVMContext(),
2343 NumBits: CGM.getDataLayout().getTypeSizeInBits(Ty: StoreVal->getType()));
2344 StoreVal = Builder.CreateBitCast(V: StoreVal, DestTy: IntTy);
2345 StoreVal = Builder.CreateZExtOrBitCast(V: StoreVal, DestTy: Int32Ty);
2346 }
2347
2348 Function *F = CGM.getIntrinsic(
2349 IID: BuiltinID == clang::ARM::BI__builtin_arm_stlex ? Intrinsic::arm_stlex
2350 : Intrinsic::arm_strex,
2351 Tys: StoreAddr->getType());
2352
2353 CallInst *CI = Builder.CreateCall(Callee: F, Args: {StoreVal, StoreAddr}, Name: "strex");
2354 CI->addParamAttr(
2355 ArgNo: 1, Attr: Attribute::get(Context&: getLLVMContext(), Kind: Attribute::ElementType, Ty: StoreTy));
2356 return CI;
2357 }
2358
2359 if (BuiltinID == clang::ARM::BI__builtin_arm_clrex) {
2360 Function *F = CGM.getIntrinsic(IID: Intrinsic::arm_clrex);
2361 return Builder.CreateCall(Callee: F);
2362 }
2363
2364 // CRC32
2365 Intrinsic::ID CRCIntrinsicID = Intrinsic::not_intrinsic;
2366 switch (BuiltinID) {
2367 case clang::ARM::BI__builtin_arm_crc32b:
2368 CRCIntrinsicID = Intrinsic::arm_crc32b; break;
2369 case clang::ARM::BI__builtin_arm_crc32cb:
2370 CRCIntrinsicID = Intrinsic::arm_crc32cb; break;
2371 case clang::ARM::BI__builtin_arm_crc32h:
2372 CRCIntrinsicID = Intrinsic::arm_crc32h; break;
2373 case clang::ARM::BI__builtin_arm_crc32ch:
2374 CRCIntrinsicID = Intrinsic::arm_crc32ch; break;
2375 case clang::ARM::BI__builtin_arm_crc32w:
2376 case clang::ARM::BI__builtin_arm_crc32d:
2377 CRCIntrinsicID = Intrinsic::arm_crc32w; break;
2378 case clang::ARM::BI__builtin_arm_crc32cw:
2379 case clang::ARM::BI__builtin_arm_crc32cd:
2380 CRCIntrinsicID = Intrinsic::arm_crc32cw; break;
2381 }
2382
2383 if (CRCIntrinsicID != Intrinsic::not_intrinsic) {
2384 Value *Arg0 = EmitScalarExpr(E: E->getArg(Arg: 0));
2385 Value *Arg1 = EmitScalarExpr(E: E->getArg(Arg: 1));
2386
2387 // crc32{c,}d intrinsics are implemented as two calls to crc32{c,}w
2388 // intrinsics, hence we need different codegen for these cases.
2389 if (BuiltinID == clang::ARM::BI__builtin_arm_crc32d ||
2390 BuiltinID == clang::ARM::BI__builtin_arm_crc32cd) {
2391 Value *C1 = llvm::ConstantInt::get(Ty: Int64Ty, V: 32);
2392 Value *Arg1a = Builder.CreateTruncOrBitCast(V: Arg1, DestTy: Int32Ty);
2393 Value *Arg1b = Builder.CreateLShr(LHS: Arg1, RHS: C1);
2394 Arg1b = Builder.CreateTruncOrBitCast(V: Arg1b, DestTy: Int32Ty);
2395
2396 Function *F = CGM.getIntrinsic(IID: CRCIntrinsicID);
2397 Value *Res = Builder.CreateCall(Callee: F, Args: {Arg0, Arg1a});
2398 return Builder.CreateCall(Callee: F, Args: {Res, Arg1b});
2399 } else {
2400 Arg1 = Builder.CreateZExtOrBitCast(V: Arg1, DestTy: Int32Ty);
2401
2402 Function *F = CGM.getIntrinsic(IID: CRCIntrinsicID);
2403 return Builder.CreateCall(Callee: F, Args: {Arg0, Arg1});
2404 }
2405 }
2406
2407 if (BuiltinID == clang::ARM::BI__builtin_arm_rsr ||
2408 BuiltinID == clang::ARM::BI__builtin_arm_rsr64 ||
2409 BuiltinID == clang::ARM::BI__builtin_arm_rsrp ||
2410 BuiltinID == clang::ARM::BI__builtin_arm_wsr ||
2411 BuiltinID == clang::ARM::BI__builtin_arm_wsr64 ||
2412 BuiltinID == clang::ARM::BI__builtin_arm_wsrp) {
2413
2414 SpecialRegisterAccessKind AccessKind = Write;
2415 if (BuiltinID == clang::ARM::BI__builtin_arm_rsr ||
2416 BuiltinID == clang::ARM::BI__builtin_arm_rsr64 ||
2417 BuiltinID == clang::ARM::BI__builtin_arm_rsrp)
2418 AccessKind = VolatileRead;
2419
2420 bool IsPointerBuiltin = BuiltinID == clang::ARM::BI__builtin_arm_rsrp ||
2421 BuiltinID == clang::ARM::BI__builtin_arm_wsrp;
2422
2423 bool Is64Bit = BuiltinID == clang::ARM::BI__builtin_arm_rsr64 ||
2424 BuiltinID == clang::ARM::BI__builtin_arm_wsr64;
2425
2426 llvm::Type *ValueType;
2427 llvm::Type *RegisterType;
2428 if (IsPointerBuiltin) {
2429 ValueType = VoidPtrTy;
2430 RegisterType = Int32Ty;
2431 } else if (Is64Bit) {
2432 ValueType = RegisterType = Int64Ty;
2433 } else {
2434 ValueType = RegisterType = Int32Ty;
2435 }
2436
2437 return EmitSpecialRegisterBuiltin(CGF&: *this, E, RegisterType, ValueType,
2438 AccessKind);
2439 }
2440
2441 if (BuiltinID == ARM::BI__builtin_sponentry) {
2442 llvm::Function *F = CGM.getIntrinsic(IID: Intrinsic::sponentry, Tys: AllocaInt8PtrTy);
2443 return Builder.CreateCall(Callee: F);
2444 }
2445
2446 // Handle MSVC intrinsics before argument evaluation to prevent double
2447 // evaluation.
2448 if (std::optional<MSVCIntrin> MsvcIntId = translateArmToMsvcIntrin(BuiltinID))
2449 return EmitMSVCBuiltinExpr(BuiltinID: *MsvcIntId, E);
2450
2451 // Deal with MVE builtins
2452 if (Value *Result = EmitARMMVEBuiltinExpr(BuiltinID, E, ReturnValue, Arch))
2453 return Result;
2454 // Handle CDE builtins
2455 if (Value *Result = EmitARMCDEBuiltinExpr(BuiltinID, E, ReturnValue, Arch))
2456 return Result;
2457
2458 // Some intrinsics are equivalent - if they are use the base intrinsic ID.
2459 auto It = llvm::find_if(Range: NEONEquivalentIntrinsicMap, P: [BuiltinID](auto &P) {
2460 return P.first == BuiltinID;
2461 });
2462 if (It != end(arr: NEONEquivalentIntrinsicMap))
2463 BuiltinID = It->second;
2464
2465 // Find out if any arguments are required to be integer constant
2466 // expressions.
2467 unsigned ICEArguments = 0;
2468 ASTContext::GetBuiltinTypeError Error;
2469 getContext().GetBuiltinType(ID: BuiltinID, Error, IntegerConstantArgs: &ICEArguments);
2470 assert(Error == ASTContext::GE_None && "Should not codegen an error");
2471
2472 auto getAlignmentValue32 = [&](Address addr) -> Value* {
2473 return Builder.getInt32(C: addr.getAlignment().getQuantity());
2474 };
2475
2476 Address PtrOp0 = Address::invalid();
2477 Address PtrOp1 = Address::invalid();
2478 SmallVector<Value*, 4> Ops;
2479 bool HasExtraArg = HasExtraNeonArgument(BuiltinID);
2480 unsigned NumArgs = E->getNumArgs() - (HasExtraArg ? 1 : 0);
2481 for (unsigned i = 0, e = NumArgs; i != e; i++) {
2482 if (i == 0) {
2483 switch (BuiltinID) {
2484 case NEON::BI__builtin_neon_vld1_v:
2485 case NEON::BI__builtin_neon_vld1q_v:
2486 case NEON::BI__builtin_neon_vld1q_lane_v:
2487 case NEON::BI__builtin_neon_vld1_lane_v:
2488 case NEON::BI__builtin_neon_vld1_dup_v:
2489 case NEON::BI__builtin_neon_vld1q_dup_v:
2490 case NEON::BI__builtin_neon_vst1_v:
2491 case NEON::BI__builtin_neon_vst1q_v:
2492 case NEON::BI__builtin_neon_vst1q_lane_v:
2493 case NEON::BI__builtin_neon_vst1_lane_v:
2494 case NEON::BI__builtin_neon_vst2_v:
2495 case NEON::BI__builtin_neon_vst2q_v:
2496 case NEON::BI__builtin_neon_vst2_lane_v:
2497 case NEON::BI__builtin_neon_vst2q_lane_v:
2498 case NEON::BI__builtin_neon_vst3_v:
2499 case NEON::BI__builtin_neon_vst3q_v:
2500 case NEON::BI__builtin_neon_vst3_lane_v:
2501 case NEON::BI__builtin_neon_vst3q_lane_v:
2502 case NEON::BI__builtin_neon_vst4_v:
2503 case NEON::BI__builtin_neon_vst4q_v:
2504 case NEON::BI__builtin_neon_vst4_lane_v:
2505 case NEON::BI__builtin_neon_vst4q_lane_v:
2506 // Get the alignment for the argument in addition to the value;
2507 // we'll use it later.
2508 PtrOp0 = EmitPointerWithAlignment(Addr: E->getArg(Arg: 0));
2509 Ops.push_back(Elt: PtrOp0.emitRawPointer(CGF&: *this));
2510 continue;
2511 }
2512 }
2513 if (i == 1) {
2514 switch (BuiltinID) {
2515 case NEON::BI__builtin_neon_vld2_v:
2516 case NEON::BI__builtin_neon_vld2q_v:
2517 case NEON::BI__builtin_neon_vld3_v:
2518 case NEON::BI__builtin_neon_vld3q_v:
2519 case NEON::BI__builtin_neon_vld4_v:
2520 case NEON::BI__builtin_neon_vld4q_v:
2521 case NEON::BI__builtin_neon_vld2_lane_v:
2522 case NEON::BI__builtin_neon_vld2q_lane_v:
2523 case NEON::BI__builtin_neon_vld3_lane_v:
2524 case NEON::BI__builtin_neon_vld3q_lane_v:
2525 case NEON::BI__builtin_neon_vld4_lane_v:
2526 case NEON::BI__builtin_neon_vld4q_lane_v:
2527 case NEON::BI__builtin_neon_vld2_dup_v:
2528 case NEON::BI__builtin_neon_vld2q_dup_v:
2529 case NEON::BI__builtin_neon_vld3_dup_v:
2530 case NEON::BI__builtin_neon_vld3q_dup_v:
2531 case NEON::BI__builtin_neon_vld4_dup_v:
2532 case NEON::BI__builtin_neon_vld4q_dup_v:
2533 // Get the alignment for the argument in addition to the value;
2534 // we'll use it later.
2535 PtrOp1 = EmitPointerWithAlignment(Addr: E->getArg(Arg: 1));
2536 Ops.push_back(Elt: PtrOp1.emitRawPointer(CGF&: *this));
2537 continue;
2538 }
2539 }
2540
2541 Ops.push_back(Elt: EmitScalarOrConstFoldImmArg(ICEArguments, Idx: i, E));
2542 }
2543
2544 switch (BuiltinID) {
2545 default: break;
2546
2547 case NEON::BI__builtin_neon_vget_lane_i8:
2548 case NEON::BI__builtin_neon_vget_lane_i16:
2549 case NEON::BI__builtin_neon_vget_lane_i32:
2550 case NEON::BI__builtin_neon_vget_lane_i64:
2551 case NEON::BI__builtin_neon_vget_lane_bf16:
2552 case NEON::BI__builtin_neon_vget_lane_f32:
2553 case NEON::BI__builtin_neon_vgetq_lane_i8:
2554 case NEON::BI__builtin_neon_vgetq_lane_i16:
2555 case NEON::BI__builtin_neon_vgetq_lane_i32:
2556 case NEON::BI__builtin_neon_vgetq_lane_i64:
2557 case NEON::BI__builtin_neon_vgetq_lane_bf16:
2558 case NEON::BI__builtin_neon_vgetq_lane_f32:
2559 case NEON::BI__builtin_neon_vduph_lane_bf16:
2560 case NEON::BI__builtin_neon_vduph_laneq_bf16:
2561 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vget_lane");
2562
2563 case NEON::BI__builtin_neon_vrndns_f32: {
2564 Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
2565 llvm::Type *Tys[] = {Arg->getType()};
2566 Function *F = CGM.getIntrinsic(IID: Intrinsic::roundeven, Tys);
2567 return Builder.CreateCall(Callee: F, Args: {Arg}, Name: "vrndn"); }
2568
2569 case NEON::BI__builtin_neon_vset_lane_i8:
2570 case NEON::BI__builtin_neon_vset_lane_i16:
2571 case NEON::BI__builtin_neon_vset_lane_i32:
2572 case NEON::BI__builtin_neon_vset_lane_i64:
2573 case NEON::BI__builtin_neon_vset_lane_bf16:
2574 case NEON::BI__builtin_neon_vset_lane_f32:
2575 case NEON::BI__builtin_neon_vsetq_lane_i8:
2576 case NEON::BI__builtin_neon_vsetq_lane_i16:
2577 case NEON::BI__builtin_neon_vsetq_lane_i32:
2578 case NEON::BI__builtin_neon_vsetq_lane_i64:
2579 case NEON::BI__builtin_neon_vsetq_lane_bf16:
2580 case NEON::BI__builtin_neon_vsetq_lane_f32:
2581 return Builder.CreateInsertElement(Vec: Ops[1], NewElt: Ops[0], Idx: Ops[2], Name: "vset_lane");
2582
2583 case NEON::BI__builtin_neon_vsha1h_u32:
2584 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_sha1h), Ops,
2585 name: "vsha1h");
2586 case NEON::BI__builtin_neon_vsha1cq_u32:
2587 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_sha1c), Ops,
2588 name: "vsha1h");
2589 case NEON::BI__builtin_neon_vsha1pq_u32:
2590 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_sha1p), Ops,
2591 name: "vsha1h");
2592 case NEON::BI__builtin_neon_vsha1mq_u32:
2593 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_sha1m), Ops,
2594 name: "vsha1h");
2595
2596 case NEON::BI__builtin_neon_vcvth_bf16_f32:
2597 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vcvtbfp2bf), Ops,
2598 name: "vcvtbfp2bf");
2599 case NEON::BI__builtin_neon_vcvt_f16_f32:
2600 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vcvtfp2hf), Ops,
2601 name: "vcvtfp2hf");
2602 case NEON::BI__builtin_neon_vcvt_f32_f16:
2603 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vcvthf2fp), Ops,
2604 name: "vcvthf2fp");
2605
2606 // The ARM _MoveToCoprocessor builtins put the input register value as
2607 // the first argument, but the LLVM intrinsic expects it as the third one.
2608 case clang::ARM::BI_MoveToCoprocessor:
2609 case clang::ARM::BI_MoveToCoprocessor2: {
2610 Function *F = CGM.getIntrinsic(IID: BuiltinID == clang::ARM::BI_MoveToCoprocessor
2611 ? Intrinsic::arm_mcr
2612 : Intrinsic::arm_mcr2);
2613 return Builder.CreateCall(Callee: F, Args: {Ops[1], Ops[2], Ops[0],
2614 Ops[3], Ops[4], Ops[5]});
2615 }
2616 }
2617
2618 // Get the last argument, which specifies the vector type.
2619 assert(HasExtraArg);
2620 const Expr *Arg = E->getArg(Arg: E->getNumArgs()-1);
2621 std::optional<llvm::APSInt> Result =
2622 Arg->getIntegerConstantExpr(Ctx: getContext());
2623 if (!Result)
2624 return nullptr;
2625
2626 if (BuiltinID == clang::ARM::BI__builtin_arm_vcvtr_f ||
2627 BuiltinID == clang::ARM::BI__builtin_arm_vcvtr_d) {
2628 // Determine the overloaded type of this builtin.
2629 llvm::Type *Ty;
2630 if (BuiltinID == clang::ARM::BI__builtin_arm_vcvtr_f)
2631 Ty = FloatTy;
2632 else
2633 Ty = DoubleTy;
2634
2635 // Determine whether this is an unsigned conversion or not.
2636 bool usgn = Result->getZExtValue() == 1;
2637 unsigned Int = usgn ? Intrinsic::arm_vcvtru : Intrinsic::arm_vcvtr;
2638
2639 // Call the appropriate intrinsic.
2640 Function *F = CGM.getIntrinsic(IID: Int, Tys: Ty);
2641 return Builder.CreateCall(Callee: F, Args: Ops, Name: "vcvtr");
2642 }
2643
2644 // Determine the type of this overloaded NEON intrinsic.
2645 NeonTypeFlags Type = Result->getZExtValue();
2646 bool usgn = Type.isUnsigned();
2647 bool rightShift = false;
2648
2649 llvm::FixedVectorType *VTy =
2650 GetNeonType(CGF: this, TypeFlags: Type, HasFastHalfType: getTarget().hasFastHalfType(), V1Ty: false,
2651 AllowBFloatArgsAndRet: getTarget().hasBFloat16Type());
2652 llvm::Type *Ty = VTy;
2653 if (!Ty)
2654 return nullptr;
2655
2656 // Many NEON builtins have identical semantics and uses in ARM and
2657 // AArch64. Emit these in a single function.
2658 auto IntrinsicMap = ArrayRef(ARMSIMDIntrinsicMap);
2659 const ARMNeonVectorIntrinsicInfo *Builtin = findARMVectorIntrinsicInMap(
2660 IntrinsicMap, BuiltinID, MapProvenSorted&: NEONSIMDIntrinsicsProvenSorted);
2661 if (Builtin)
2662 return EmitCommonNeonBuiltinExpr(
2663 BuiltinID: Builtin->BuiltinID, LLVMIntrinsic: Builtin->LLVMIntrinsic, AltLLVMIntrinsic: Builtin->AltLLVMIntrinsic,
2664 NameHint: Builtin->NameHint, Modifier: Builtin->TypeModifier, E, Ops, PtrOp0, PtrOp1, Arch);
2665
2666 unsigned Int;
2667 switch (BuiltinID) {
2668 default: return nullptr;
2669 case NEON::BI__builtin_neon_vld1q_lane_v:
2670 // Handle 64-bit integer elements as a special case. Use shuffles of
2671 // one-element vectors to avoid poor code for i64 in the backend.
2672 if (VTy->getElementType()->isIntegerTy(BitWidth: 64)) {
2673 // Extract the other lane.
2674 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
2675 int Lane = cast<ConstantInt>(Val: Ops[2])->getZExtValue();
2676 Value *SV = llvm::ConstantVector::get(V: ConstantInt::get(Ty: Int32Ty, V: 1-Lane));
2677 Ops[1] = Builder.CreateShuffleVector(V1: Ops[1], V2: Ops[1], Mask: SV);
2678 // Load the value as a one-element vector.
2679 Ty = llvm::FixedVectorType::get(ElementType: VTy->getElementType(), NumElts: 1);
2680 llvm::Type *Tys[] = {Ty, Int8PtrTy};
2681 Function *F = CGM.getIntrinsic(IID: Intrinsic::arm_neon_vld1, Tys);
2682 Value *Align = getAlignmentValue32(PtrOp0);
2683 Value *Ld = Builder.CreateCall(Callee: F, Args: {Ops[0], Align});
2684 // Combine them.
2685 int Indices[] = {1 - Lane, Lane};
2686 return Builder.CreateShuffleVector(V1: Ops[1], V2: Ld, Mask: Indices, Name: "vld1q_lane");
2687 }
2688 [[fallthrough]];
2689 case NEON::BI__builtin_neon_vld1_lane_v: {
2690 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
2691 PtrOp0 = PtrOp0.withElementType(ElemTy: VTy->getElementType());
2692 Value *Ld = Builder.CreateLoad(Addr: PtrOp0);
2693 return Builder.CreateInsertElement(Vec: Ops[1], NewElt: Ld, Idx: Ops[2], Name: "vld1_lane");
2694 }
2695 case NEON::BI__builtin_neon_vqrshrn_n_v:
2696 Int =
2697 usgn ? Intrinsic::arm_neon_vqrshiftnu : Intrinsic::arm_neon_vqrshiftns;
2698 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vqrshrn_n",
2699 shift: 1, rightshift: true);
2700 case NEON::BI__builtin_neon_vqrshrun_n_v:
2701 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vqrshiftnsu, Tys: Ty),
2702 Ops, name: "vqrshrun_n", shift: 1, rightshift: true);
2703 case NEON::BI__builtin_neon_vqshrn_n_v:
2704 Int = usgn ? Intrinsic::arm_neon_vqshiftnu : Intrinsic::arm_neon_vqshiftns;
2705 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vqshrn_n",
2706 shift: 1, rightshift: true);
2707 case NEON::BI__builtin_neon_vqshrun_n_v:
2708 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vqshiftnsu, Tys: Ty),
2709 Ops, name: "vqshrun_n", shift: 1, rightshift: true);
2710 case NEON::BI__builtin_neon_vrecpe_v:
2711 case NEON::BI__builtin_neon_vrecpeq_v:
2712 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vrecpe, Tys: Ty),
2713 Ops, name: "vrecpe");
2714 case NEON::BI__builtin_neon_vrshrn_n_v:
2715 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vrshiftn, Tys: Ty),
2716 Ops, name: "vrshrn_n", shift: 1, rightshift: true);
2717 case NEON::BI__builtin_neon_vrsra_n_v:
2718 case NEON::BI__builtin_neon_vrsraq_n_v:
2719 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
2720 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
2721 Ops[2] = EmitNeonShiftVector(V: Ops[2], Ty, neg: true);
2722 Int = usgn ? Intrinsic::arm_neon_vrshiftu : Intrinsic::arm_neon_vrshifts;
2723 Ops[1] = Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Int, Tys: Ty), Args: {Ops[1], Ops[2]});
2724 return Builder.CreateAdd(LHS: Ops[0], RHS: Ops[1], Name: "vrsra_n");
2725 case NEON::BI__builtin_neon_vsri_n_v:
2726 case NEON::BI__builtin_neon_vsriq_n_v:
2727 rightShift = true;
2728 [[fallthrough]];
2729 case NEON::BI__builtin_neon_vsli_n_v:
2730 case NEON::BI__builtin_neon_vsliq_n_v:
2731 Ops[2] = EmitNeonShiftVector(V: Ops[2], Ty, neg: rightShift);
2732 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vshiftins, Tys: Ty),
2733 Ops, name: "vsli_n");
2734 case NEON::BI__builtin_neon_vsra_n_v:
2735 case NEON::BI__builtin_neon_vsraq_n_v:
2736 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
2737 Ops[1] = EmitNeonRShiftImm(Vec: Ops[1], Shift: Ops[2], Ty, usgn, name: "vsra_n");
2738 return Builder.CreateAdd(LHS: Ops[0], RHS: Ops[1]);
2739 case NEON::BI__builtin_neon_vst1q_lane_v:
2740 // Handle 64-bit integer elements as a special case. Use a shuffle to get
2741 // a one-element vector and avoid poor code for i64 in the backend.
2742 if (VTy->getElementType()->isIntegerTy(BitWidth: 64)) {
2743 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
2744 Value *SV = llvm::ConstantVector::get(V: cast<llvm::Constant>(Val: Ops[2]));
2745 Ops[1] = Builder.CreateShuffleVector(V1: Ops[1], V2: Ops[1], Mask: SV);
2746 Ops[2] = getAlignmentValue32(PtrOp0);
2747 llvm::Type *Tys[] = {Int8PtrTy, Ops[1]->getType()};
2748 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vst1,
2749 Tys), Args: Ops);
2750 }
2751 [[fallthrough]];
2752 case NEON::BI__builtin_neon_vst1_lane_v: {
2753 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
2754 Ops[1] = Builder.CreateExtractElement(Vec: Ops[1], Idx: Ops[2]);
2755 return Builder.CreateStore(Val: Ops[1],
2756 Addr: PtrOp0.withElementType(ElemTy: Ops[1]->getType()));
2757 }
2758 case NEON::BI__builtin_neon_vtbl1_v:
2759 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vtbl1),
2760 Ops, name: "vtbl1");
2761 case NEON::BI__builtin_neon_vtbl2_v:
2762 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vtbl2),
2763 Ops, name: "vtbl2");
2764 case NEON::BI__builtin_neon_vtbl3_v:
2765 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vtbl3),
2766 Ops, name: "vtbl3");
2767 case NEON::BI__builtin_neon_vtbl4_v:
2768 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vtbl4),
2769 Ops, name: "vtbl4");
2770 case NEON::BI__builtin_neon_vtbx1_v:
2771 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vtbx1),
2772 Ops, name: "vtbx1");
2773 case NEON::BI__builtin_neon_vtbx2_v:
2774 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vtbx2),
2775 Ops, name: "vtbx2");
2776 case NEON::BI__builtin_neon_vtbx3_v:
2777 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vtbx3),
2778 Ops, name: "vtbx3");
2779 case NEON::BI__builtin_neon_vtbx4_v:
2780 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::arm_neon_vtbx4),
2781 Ops, name: "vtbx4");
2782 }
2783}
2784
2785template<typename Integer>
2786static Integer GetIntegerConstantValue(const Expr *E, ASTContext &Context) {
2787 return E->getIntegerConstantExpr(Ctx: Context)->getExtValue();
2788}
2789
2790static llvm::Value *SignOrZeroExtend(CGBuilderTy &Builder, llvm::Value *V,
2791 llvm::Type *T, bool Unsigned) {
2792 // Helper function called by Tablegen-constructed ARM MVE builtin codegen,
2793 // which finds it convenient to specify signed/unsigned as a boolean flag.
2794 return Unsigned ? Builder.CreateZExt(V, DestTy: T) : Builder.CreateSExt(V, DestTy: T);
2795}
2796
2797static llvm::Value *MVEImmediateShr(CGBuilderTy &Builder, llvm::Value *V,
2798 uint32_t Shift, bool Unsigned) {
2799 // MVE helper function for integer shift right. This must handle signed vs
2800 // unsigned, and also deal specially with the case where the shift count is
2801 // equal to the lane size. In LLVM IR, an LShr with that parameter would be
2802 // undefined behavior, but in MVE it's legal, so we must convert it to code
2803 // that is not undefined in IR.
2804 unsigned LaneBits = cast<llvm::VectorType>(Val: V->getType())
2805 ->getElementType()
2806 ->getPrimitiveSizeInBits();
2807 if (Shift == LaneBits) {
2808 // An unsigned shift of the full lane size always generates zero, so we can
2809 // simply emit a zero vector. A signed shift of the full lane size does the
2810 // same thing as shifting by one bit fewer.
2811 if (Unsigned)
2812 return llvm::Constant::getNullValue(Ty: V->getType());
2813 else
2814 --Shift;
2815 }
2816 return Unsigned ? Builder.CreateLShr(LHS: V, RHS: Shift) : Builder.CreateAShr(LHS: V, RHS: Shift);
2817}
2818
2819static llvm::Value *ARMMVEVectorSplat(CGBuilderTy &Builder, llvm::Value *V) {
2820 // MVE-specific helper function for a vector splat, which infers the element
2821 // count of the output vector by knowing that MVE vectors are all 128 bits
2822 // wide.
2823 unsigned Elements = 128 / V->getType()->getPrimitiveSizeInBits();
2824 return Builder.CreateVectorSplat(NumElts: Elements, V);
2825}
2826
2827static llvm::Value *ARMMVEVectorReinterpret(CGBuilderTy &Builder,
2828 CodeGenFunction *CGF,
2829 llvm::Value *V,
2830 llvm::Type *DestType) {
2831 // Convert one MVE vector type into another by reinterpreting its in-register
2832 // format.
2833 //
2834 // Little-endian, this is identical to a bitcast (which reinterprets the
2835 // memory format). But big-endian, they're not necessarily the same, because
2836 // the register and memory formats map to each other differently depending on
2837 // the lane size.
2838 //
2839 // We generate a bitcast whenever we can (if we're little-endian, or if the
2840 // lane sizes are the same anyway). Otherwise we fall back to an IR intrinsic
2841 // that performs the different kind of reinterpretation.
2842 if (CGF->getTarget().isBigEndian() &&
2843 V->getType()->getScalarSizeInBits() != DestType->getScalarSizeInBits()) {
2844 return Builder.CreateCall(
2845 Callee: CGF->CGM.getIntrinsic(IID: Intrinsic::arm_mve_vreinterpretq,
2846 Tys: {DestType, V->getType()}),
2847 Args: V);
2848 } else {
2849 return Builder.CreateBitCast(V, DestTy: DestType);
2850 }
2851}
2852
2853static llvm::Value *VectorUnzip(CGBuilderTy &Builder, llvm::Value *V, bool Odd) {
2854 // Make a shufflevector that extracts every other element of a vector (evens
2855 // or odds, as desired).
2856 SmallVector<int, 16> Indices;
2857 unsigned InputElements =
2858 cast<llvm::FixedVectorType>(Val: V->getType())->getNumElements();
2859 for (unsigned i = 0; i < InputElements; i += 2)
2860 Indices.push_back(Elt: i + Odd);
2861 return Builder.CreateShuffleVector(V, Mask: Indices);
2862}
2863
2864static llvm::Value *VectorZip(CGBuilderTy &Builder, llvm::Value *V0,
2865 llvm::Value *V1) {
2866 // Make a shufflevector that interleaves two vectors element by element.
2867 assert(V0->getType() == V1->getType() && "Can't zip different vector types");
2868 SmallVector<int, 16> Indices;
2869 unsigned InputElements =
2870 cast<llvm::FixedVectorType>(Val: V0->getType())->getNumElements();
2871 for (unsigned i = 0; i < InputElements; i++) {
2872 Indices.push_back(Elt: i);
2873 Indices.push_back(Elt: i + InputElements);
2874 }
2875 return Builder.CreateShuffleVector(V1: V0, V2: V1, Mask: Indices);
2876}
2877
2878template<unsigned HighBit, unsigned OtherBits>
2879static llvm::Value *ARMMVEConstantSplat(CGBuilderTy &Builder, llvm::Type *VT) {
2880 // MVE-specific helper function to make a vector splat of a constant such as
2881 // UINT_MAX or INT_MIN, in which all bits below the highest one are equal.
2882 llvm::Type *T = cast<llvm::VectorType>(Val: VT)->getElementType();
2883 unsigned LaneBits = T->getPrimitiveSizeInBits();
2884 uint32_t Value = HighBit << (LaneBits - 1);
2885 if (OtherBits)
2886 Value |= (1UL << (LaneBits - 1)) - 1;
2887 llvm::Value *Lane = llvm::ConstantInt::get(Ty: T, V: Value);
2888 return ARMMVEVectorSplat(Builder, V: Lane);
2889}
2890
2891static llvm::Value *ARMMVEVectorElementReverse(CGBuilderTy &Builder,
2892 llvm::Value *V,
2893 unsigned ReverseWidth) {
2894 // MVE-specific helper function which reverses the elements of a
2895 // vector within every (ReverseWidth)-bit collection of lanes.
2896 SmallVector<int, 16> Indices;
2897 unsigned LaneSize = V->getType()->getScalarSizeInBits();
2898 unsigned Elements = 128 / LaneSize;
2899 unsigned Mask = ReverseWidth / LaneSize - 1;
2900 for (unsigned i = 0; i < Elements; i++)
2901 Indices.push_back(Elt: i ^ Mask);
2902 return Builder.CreateShuffleVector(V, Mask: Indices);
2903}
2904
2905static llvm::Value *ARMMVECreateSIToFP(CGBuilderTy &Builder,
2906 CodeGenFunction *CGF, llvm::Value *V,
2907 llvm::Type *Ty) {
2908 return Builder.CreateCall(
2909 Callee: CGF->CGM.getIntrinsic(IID: Intrinsic::arm_mve_vcvt_fp_int, Tys: {Ty, V->getType()}),
2910 Args: {V, llvm::ConstantInt::get(Ty: Builder.getInt32Ty(), V: 0)});
2911}
2912
2913static llvm::Value *ARMMVECreateUIToFP(CGBuilderTy &Builder,
2914 CodeGenFunction *CGF, llvm::Value *V,
2915 llvm::Type *Ty) {
2916 return Builder.CreateCall(
2917 Callee: CGF->CGM.getIntrinsic(IID: Intrinsic::arm_mve_vcvt_fp_int, Tys: {Ty, V->getType()}),
2918 Args: {V, llvm::ConstantInt::get(Ty: Builder.getInt32Ty(), V: 1)});
2919}
2920
2921static llvm::Value *ARMMVECreateFPToSI(CGBuilderTy &Builder,
2922 CodeGenFunction *CGF, llvm::Value *V,
2923 llvm::Type *Ty) {
2924 return Builder.CreateCall(
2925 Callee: CGF->CGM.getIntrinsic(IID: Intrinsic::arm_mve_vcvt_int_fp, Tys: {Ty, V->getType()}),
2926 Args: {V, llvm::ConstantInt::get(Ty: Builder.getInt32Ty(), V: 0)});
2927}
2928
2929static llvm::Value *ARMMVECreateFPToUI(CGBuilderTy &Builder,
2930 CodeGenFunction *CGF, llvm::Value *V,
2931 llvm::Type *Ty) {
2932 return Builder.CreateCall(
2933 Callee: CGF->CGM.getIntrinsic(IID: Intrinsic::arm_mve_vcvt_int_fp, Tys: {Ty, V->getType()}),
2934 Args: {V, llvm::ConstantInt::get(Ty: Builder.getInt32Ty(), V: 1)});
2935}
2936
2937Value *CodeGenFunction::EmitARMMVEBuiltinExpr(unsigned BuiltinID,
2938 const CallExpr *E,
2939 ReturnValueSlot ReturnValue,
2940 llvm::Triple::ArchType Arch) {
2941 enum class CustomCodeGen { VLD24, VST24 } CustomCodeGenType;
2942 Intrinsic::ID IRIntr;
2943 unsigned NumVectors;
2944
2945 // Code autogenerated by Tablegen will handle all the simple builtins.
2946 switch (BuiltinID) {
2947 #include "clang/Basic/arm_mve_builtin_cg.inc"
2948
2949 // If we didn't match an MVE builtin id at all, go back to the
2950 // main EmitARMBuiltinExpr.
2951 default:
2952 return nullptr;
2953 }
2954
2955 // Anything that breaks from that switch is an MVE builtin that
2956 // needs handwritten code to generate.
2957
2958 switch (CustomCodeGenType) {
2959
2960 case CustomCodeGen::VLD24: {
2961 llvm::SmallVector<Value *, 4> Ops;
2962 llvm::SmallVector<llvm::Type *, 4> Tys;
2963
2964 auto MvecCType = E->getType();
2965 auto MvecLType = ConvertType(T: MvecCType);
2966 assert(MvecLType->isStructTy() &&
2967 "Return type for vld[24]q should be a struct");
2968 assert(MvecLType->getStructNumElements() == 1 &&
2969 "Return-type struct for vld[24]q should have one element");
2970 auto MvecLTypeInner = MvecLType->getStructElementType(N: 0);
2971 assert(MvecLTypeInner->isArrayTy() &&
2972 "Return-type struct for vld[24]q should contain an array");
2973 assert(MvecLTypeInner->getArrayNumElements() == NumVectors &&
2974 "Array member of return-type struct vld[24]q has wrong length");
2975 auto VecLType = MvecLTypeInner->getArrayElementType();
2976
2977 Tys.push_back(Elt: VecLType);
2978
2979 auto Addr = E->getArg(Arg: 0);
2980 Ops.push_back(Elt: EmitScalarExpr(E: Addr));
2981 Tys.push_back(Elt: ConvertType(T: Addr->getType()));
2982
2983 Function *F = CGM.getIntrinsic(IID: IRIntr, Tys: ArrayRef(Tys));
2984 Value *LoadResult = Builder.CreateCall(Callee: F, Args: Ops);
2985 Value *MvecOut = PoisonValue::get(T: MvecLType);
2986 for (unsigned i = 0; i < NumVectors; ++i) {
2987 Value *Vec = Builder.CreateExtractValue(Agg: LoadResult, Idxs: i);
2988 MvecOut = Builder.CreateInsertValue(Agg: MvecOut, Val: Vec, Idxs: {0, i});
2989 }
2990
2991 if (ReturnValue.isNull())
2992 return MvecOut;
2993 else
2994 return Builder.CreateStore(Val: MvecOut, Addr: ReturnValue.getAddress());
2995 }
2996
2997 case CustomCodeGen::VST24: {
2998 llvm::SmallVector<Value *, 4> Ops;
2999 llvm::SmallVector<llvm::Type *, 4> Tys;
3000
3001 auto Addr = E->getArg(Arg: 0);
3002 Ops.push_back(Elt: EmitScalarExpr(E: Addr));
3003 Tys.push_back(Elt: ConvertType(T: Addr->getType()));
3004
3005 auto MvecCType = E->getArg(Arg: 1)->getType();
3006 auto MvecLType = ConvertType(T: MvecCType);
3007 assert(MvecLType->isStructTy() && "Data type for vst2q should be a struct");
3008 assert(MvecLType->getStructNumElements() == 1 &&
3009 "Data-type struct for vst2q should have one element");
3010 auto MvecLTypeInner = MvecLType->getStructElementType(N: 0);
3011 assert(MvecLTypeInner->isArrayTy() &&
3012 "Data-type struct for vst2q should contain an array");
3013 assert(MvecLTypeInner->getArrayNumElements() == NumVectors &&
3014 "Array member of return-type struct vld[24]q has wrong length");
3015 auto VecLType = MvecLTypeInner->getArrayElementType();
3016
3017 Tys.push_back(Elt: VecLType);
3018
3019 AggValueSlot MvecSlot = CreateAggTemp(T: MvecCType);
3020 EmitAggExpr(E: E->getArg(Arg: 1), AS: MvecSlot);
3021 auto Mvec = Builder.CreateLoad(Addr: MvecSlot.getAddress());
3022 for (unsigned i = 0; i < NumVectors; i++)
3023 Ops.push_back(Elt: Builder.CreateExtractValue(Agg: Mvec, Idxs: {0, i}));
3024
3025 Function *F = CGM.getIntrinsic(IID: IRIntr, Tys: ArrayRef(Tys));
3026 Value *ToReturn = nullptr;
3027 for (unsigned i = 0; i < NumVectors; i++) {
3028 Ops.push_back(Elt: llvm::ConstantInt::get(Ty: Int32Ty, V: i));
3029 ToReturn = Builder.CreateCall(Callee: F, Args: Ops);
3030 Ops.pop_back();
3031 }
3032 return ToReturn;
3033 }
3034 }
3035 llvm_unreachable("unknown custom codegen type.");
3036}
3037
3038Value *CodeGenFunction::EmitARMCDEBuiltinExpr(unsigned BuiltinID,
3039 const CallExpr *E,
3040 ReturnValueSlot ReturnValue,
3041 llvm::Triple::ArchType Arch) {
3042 switch (BuiltinID) {
3043 default:
3044 return nullptr;
3045#include "clang/Basic/arm_cde_builtin_cg.inc"
3046 }
3047}
3048
3049static Value *EmitAArch64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID,
3050 const CallExpr *E,
3051 SmallVectorImpl<Value *> &Ops,
3052 llvm::Triple::ArchType Arch) {
3053 unsigned int Int = 0;
3054 const char *s = nullptr;
3055
3056 switch (BuiltinID) {
3057 default:
3058 return nullptr;
3059 case NEON::BI__builtin_neon_vtbl1_v:
3060 case NEON::BI__builtin_neon_vqtbl1_v:
3061 case NEON::BI__builtin_neon_vqtbl1q_v:
3062 case NEON::BI__builtin_neon_vtbl2_v:
3063 case NEON::BI__builtin_neon_vqtbl2_v:
3064 case NEON::BI__builtin_neon_vqtbl2q_v:
3065 case NEON::BI__builtin_neon_vtbl3_v:
3066 case NEON::BI__builtin_neon_vqtbl3_v:
3067 case NEON::BI__builtin_neon_vqtbl3q_v:
3068 case NEON::BI__builtin_neon_vtbl4_v:
3069 case NEON::BI__builtin_neon_vqtbl4_v:
3070 case NEON::BI__builtin_neon_vqtbl4q_v:
3071 break;
3072 case NEON::BI__builtin_neon_vtbx1_v:
3073 case NEON::BI__builtin_neon_vqtbx1_v:
3074 case NEON::BI__builtin_neon_vqtbx1q_v:
3075 case NEON::BI__builtin_neon_vtbx2_v:
3076 case NEON::BI__builtin_neon_vqtbx2_v:
3077 case NEON::BI__builtin_neon_vqtbx2q_v:
3078 case NEON::BI__builtin_neon_vtbx3_v:
3079 case NEON::BI__builtin_neon_vqtbx3_v:
3080 case NEON::BI__builtin_neon_vqtbx3q_v:
3081 case NEON::BI__builtin_neon_vtbx4_v:
3082 case NEON::BI__builtin_neon_vqtbx4_v:
3083 case NEON::BI__builtin_neon_vqtbx4q_v:
3084 break;
3085 }
3086
3087 assert(E->getNumArgs() >= 3);
3088
3089 // Get the last argument, which specifies the vector type.
3090 const Expr *Arg = E->getArg(Arg: E->getNumArgs() - 1);
3091 std::optional<llvm::APSInt> Result =
3092 Arg->getIntegerConstantExpr(Ctx: CGF.getContext());
3093 if (!Result)
3094 return nullptr;
3095
3096 // Determine the type of this overloaded NEON intrinsic.
3097 NeonTypeFlags Type = Result->getZExtValue();
3098 llvm::FixedVectorType *Ty = GetNeonType(CGF: &CGF, TypeFlags: Type);
3099 if (!Ty)
3100 return nullptr;
3101
3102 CodeGen::CGBuilderTy &Builder = CGF.Builder;
3103
3104 // AArch64 scalar builtins are not overloaded, they do not have an extra
3105 // argument that specifies the vector type, need to handle each case.
3106 switch (BuiltinID) {
3107 case NEON::BI__builtin_neon_vtbl1_v: {
3108 return packTBLDVectorList(CGF, Ops: ArrayRef(Ops).slice(N: 0, M: 1), ExtOp: nullptr, IndexOp: Ops[1],
3109 ResTy: Ty, IntID: Intrinsic::aarch64_neon_tbl1, Name: "vtbl1");
3110 }
3111 case NEON::BI__builtin_neon_vtbl2_v: {
3112 return packTBLDVectorList(CGF, Ops: ArrayRef(Ops).slice(N: 0, M: 2), ExtOp: nullptr, IndexOp: Ops[2],
3113 ResTy: Ty, IntID: Intrinsic::aarch64_neon_tbl1, Name: "vtbl1");
3114 }
3115 case NEON::BI__builtin_neon_vtbl3_v: {
3116 return packTBLDVectorList(CGF, Ops: ArrayRef(Ops).slice(N: 0, M: 3), ExtOp: nullptr, IndexOp: Ops[3],
3117 ResTy: Ty, IntID: Intrinsic::aarch64_neon_tbl2, Name: "vtbl2");
3118 }
3119 case NEON::BI__builtin_neon_vtbl4_v: {
3120 return packTBLDVectorList(CGF, Ops: ArrayRef(Ops).slice(N: 0, M: 4), ExtOp: nullptr, IndexOp: Ops[4],
3121 ResTy: Ty, IntID: Intrinsic::aarch64_neon_tbl2, Name: "vtbl2");
3122 }
3123 case NEON::BI__builtin_neon_vtbx1_v: {
3124 Value *TblRes =
3125 packTBLDVectorList(CGF, Ops: ArrayRef(Ops).slice(N: 1, M: 1), ExtOp: nullptr, IndexOp: Ops[2], ResTy: Ty,
3126 IntID: Intrinsic::aarch64_neon_tbl1, Name: "vtbl1");
3127
3128 llvm::Constant *EightV = ConstantInt::get(Ty, V: 8);
3129 Value *CmpRes = Builder.CreateICmp(P: ICmpInst::ICMP_UGE, LHS: Ops[2], RHS: EightV);
3130 CmpRes = Builder.CreateSExt(V: CmpRes, DestTy: Ty);
3131
3132 Value *EltsFromInput = Builder.CreateAnd(LHS: CmpRes, RHS: Ops[0]);
3133 Value *EltsFromTbl = Builder.CreateAnd(LHS: Builder.CreateNot(V: CmpRes), RHS: TblRes);
3134 return Builder.CreateOr(LHS: EltsFromInput, RHS: EltsFromTbl, Name: "vtbx");
3135 }
3136 case NEON::BI__builtin_neon_vtbx2_v: {
3137 return packTBLDVectorList(CGF, Ops: ArrayRef(Ops).slice(N: 1, M: 2), ExtOp: Ops[0], IndexOp: Ops[3],
3138 ResTy: Ty, IntID: Intrinsic::aarch64_neon_tbx1, Name: "vtbx1");
3139 }
3140 case NEON::BI__builtin_neon_vtbx3_v: {
3141 Value *TblRes =
3142 packTBLDVectorList(CGF, Ops: ArrayRef(Ops).slice(N: 1, M: 3), ExtOp: nullptr, IndexOp: Ops[4], ResTy: Ty,
3143 IntID: Intrinsic::aarch64_neon_tbl2, Name: "vtbl2");
3144
3145 llvm::Constant *TwentyFourV = ConstantInt::get(Ty, V: 24);
3146 Value *CmpRes = Builder.CreateICmp(P: ICmpInst::ICMP_UGE, LHS: Ops[4],
3147 RHS: TwentyFourV);
3148 CmpRes = Builder.CreateSExt(V: CmpRes, DestTy: Ty);
3149
3150 Value *EltsFromInput = Builder.CreateAnd(LHS: CmpRes, RHS: Ops[0]);
3151 Value *EltsFromTbl = Builder.CreateAnd(LHS: Builder.CreateNot(V: CmpRes), RHS: TblRes);
3152 return Builder.CreateOr(LHS: EltsFromInput, RHS: EltsFromTbl, Name: "vtbx");
3153 }
3154 case NEON::BI__builtin_neon_vtbx4_v: {
3155 return packTBLDVectorList(CGF, Ops: ArrayRef(Ops).slice(N: 1, M: 4), ExtOp: Ops[0], IndexOp: Ops[5],
3156 ResTy: Ty, IntID: Intrinsic::aarch64_neon_tbx2, Name: "vtbx2");
3157 }
3158 case NEON::BI__builtin_neon_vqtbl1_v:
3159 case NEON::BI__builtin_neon_vqtbl1q_v:
3160 Int = Intrinsic::aarch64_neon_tbl1; s = "vtbl1"; break;
3161 case NEON::BI__builtin_neon_vqtbl2_v:
3162 case NEON::BI__builtin_neon_vqtbl2q_v: {
3163 Int = Intrinsic::aarch64_neon_tbl2; s = "vtbl2"; break;
3164 case NEON::BI__builtin_neon_vqtbl3_v:
3165 case NEON::BI__builtin_neon_vqtbl3q_v:
3166 Int = Intrinsic::aarch64_neon_tbl3; s = "vtbl3"; break;
3167 case NEON::BI__builtin_neon_vqtbl4_v:
3168 case NEON::BI__builtin_neon_vqtbl4q_v:
3169 Int = Intrinsic::aarch64_neon_tbl4; s = "vtbl4"; break;
3170 case NEON::BI__builtin_neon_vqtbx1_v:
3171 case NEON::BI__builtin_neon_vqtbx1q_v:
3172 Int = Intrinsic::aarch64_neon_tbx1; s = "vtbx1"; break;
3173 case NEON::BI__builtin_neon_vqtbx2_v:
3174 case NEON::BI__builtin_neon_vqtbx2q_v:
3175 Int = Intrinsic::aarch64_neon_tbx2; s = "vtbx2"; break;
3176 case NEON::BI__builtin_neon_vqtbx3_v:
3177 case NEON::BI__builtin_neon_vqtbx3q_v:
3178 Int = Intrinsic::aarch64_neon_tbx3; s = "vtbx3"; break;
3179 case NEON::BI__builtin_neon_vqtbx4_v:
3180 case NEON::BI__builtin_neon_vqtbx4q_v:
3181 Int = Intrinsic::aarch64_neon_tbx4; s = "vtbx4"; break;
3182 }
3183 }
3184
3185 if (!Int)
3186 return nullptr;
3187
3188 Function *F = CGF.CGM.getIntrinsic(IID: Int, Tys: Ty);
3189 return CGF.EmitNeonCall(F, Ops, name: s);
3190}
3191
3192Value *CodeGenFunction::vectorWrapScalar16(Value *Op) {
3193 auto *VTy = llvm::FixedVectorType::get(ElementType: Int16Ty, NumElts: 4);
3194 Op = Builder.CreateBitCast(V: Op, DestTy: Int16Ty);
3195 Value *V = PoisonValue::get(T: VTy);
3196 llvm::Constant *CI = ConstantInt::get(Ty: SizeTy, V: 0);
3197 Op = Builder.CreateInsertElement(Vec: V, NewElt: Op, Idx: CI);
3198 return Op;
3199}
3200
3201/// SVEBuiltinMemEltTy - Returns the memory element type for this memory
3202/// access builtin. Only required if it can't be inferred from the base pointer
3203/// operand.
3204llvm::Type *CodeGenFunction::SVEBuiltinMemEltTy(const SVETypeFlags &TypeFlags) {
3205 switch (TypeFlags.getMemEltType()) {
3206 case SVETypeFlags::MemEltTyDefault:
3207 return getEltType(TypeFlags);
3208 case SVETypeFlags::MemEltTyInt8:
3209 return Builder.getInt8Ty();
3210 case SVETypeFlags::MemEltTyInt16:
3211 return Builder.getInt16Ty();
3212 case SVETypeFlags::MemEltTyInt32:
3213 return Builder.getInt32Ty();
3214 case SVETypeFlags::MemEltTyInt64:
3215 return Builder.getInt64Ty();
3216 }
3217 llvm_unreachable("Unknown MemEltType");
3218}
3219
3220llvm::Type *CodeGenFunction::getEltType(const SVETypeFlags &TypeFlags) {
3221 switch (TypeFlags.getEltType()) {
3222 default:
3223 llvm_unreachable("Invalid SVETypeFlag!");
3224
3225 case SVETypeFlags::EltTyMFloat8:
3226 case SVETypeFlags::EltTyInt8:
3227 return Builder.getInt8Ty();
3228 case SVETypeFlags::EltTyInt16:
3229 return Builder.getInt16Ty();
3230 case SVETypeFlags::EltTyInt32:
3231 return Builder.getInt32Ty();
3232 case SVETypeFlags::EltTyInt64:
3233 return Builder.getInt64Ty();
3234 case SVETypeFlags::EltTyInt128:
3235 return Builder.getInt128Ty();
3236
3237 case SVETypeFlags::EltTyFloat16:
3238 return Builder.getHalfTy();
3239 case SVETypeFlags::EltTyFloat32:
3240 return Builder.getFloatTy();
3241 case SVETypeFlags::EltTyFloat64:
3242 return Builder.getDoubleTy();
3243
3244 case SVETypeFlags::EltTyBFloat16:
3245 return Builder.getBFloatTy();
3246
3247 case SVETypeFlags::EltTyBool8:
3248 case SVETypeFlags::EltTyBool16:
3249 case SVETypeFlags::EltTyBool32:
3250 case SVETypeFlags::EltTyBool64:
3251 return Builder.getInt1Ty();
3252 }
3253}
3254
3255// Return the llvm predicate vector type corresponding to the specified element
3256// TypeFlags.
3257llvm::ScalableVectorType *
3258CodeGenFunction::getSVEPredType(const SVETypeFlags &TypeFlags) {
3259 switch (TypeFlags.getEltType()) {
3260 default: llvm_unreachable("Unhandled SVETypeFlag!");
3261
3262 case SVETypeFlags::EltTyInt8:
3263 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 16);
3264 case SVETypeFlags::EltTyInt16:
3265 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 8);
3266 case SVETypeFlags::EltTyInt32:
3267 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 4);
3268 case SVETypeFlags::EltTyInt64:
3269 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 2);
3270
3271 case SVETypeFlags::EltTyBFloat16:
3272 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 8);
3273 case SVETypeFlags::EltTyFloat16:
3274 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 8);
3275 case SVETypeFlags::EltTyFloat32:
3276 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 4);
3277 case SVETypeFlags::EltTyFloat64:
3278 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 2);
3279
3280 case SVETypeFlags::EltTyBool8:
3281 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 16);
3282 case SVETypeFlags::EltTyBool16:
3283 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 8);
3284 case SVETypeFlags::EltTyBool32:
3285 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 4);
3286 case SVETypeFlags::EltTyBool64:
3287 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 2);
3288 }
3289}
3290
3291// Return the llvm vector type corresponding to the specified element TypeFlags.
3292llvm::ScalableVectorType *
3293CodeGenFunction::getSVEType(const SVETypeFlags &TypeFlags) {
3294 switch (TypeFlags.getEltType()) {
3295 default:
3296 llvm_unreachable("Invalid SVETypeFlag!");
3297
3298 case SVETypeFlags::EltTyInt8:
3299 return llvm::ScalableVectorType::get(ElementType: Builder.getInt8Ty(), MinNumElts: 16);
3300 case SVETypeFlags::EltTyInt16:
3301 return llvm::ScalableVectorType::get(ElementType: Builder.getInt16Ty(), MinNumElts: 8);
3302 case SVETypeFlags::EltTyInt32:
3303 return llvm::ScalableVectorType::get(ElementType: Builder.getInt32Ty(), MinNumElts: 4);
3304 case SVETypeFlags::EltTyInt64:
3305 return llvm::ScalableVectorType::get(ElementType: Builder.getInt64Ty(), MinNumElts: 2);
3306
3307 case SVETypeFlags::EltTyMFloat8:
3308 return llvm::ScalableVectorType::get(ElementType: Builder.getInt8Ty(), MinNumElts: 16);
3309 case SVETypeFlags::EltTyFloat16:
3310 return llvm::ScalableVectorType::get(ElementType: Builder.getHalfTy(), MinNumElts: 8);
3311 case SVETypeFlags::EltTyBFloat16:
3312 return llvm::ScalableVectorType::get(ElementType: Builder.getBFloatTy(), MinNumElts: 8);
3313 case SVETypeFlags::EltTyFloat32:
3314 return llvm::ScalableVectorType::get(ElementType: Builder.getFloatTy(), MinNumElts: 4);
3315 case SVETypeFlags::EltTyFloat64:
3316 return llvm::ScalableVectorType::get(ElementType: Builder.getDoubleTy(), MinNumElts: 2);
3317
3318 case SVETypeFlags::EltTyBool8:
3319 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 16);
3320 case SVETypeFlags::EltTyBool16:
3321 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 8);
3322 case SVETypeFlags::EltTyBool32:
3323 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 4);
3324 case SVETypeFlags::EltTyBool64:
3325 return llvm::ScalableVectorType::get(ElementType: Builder.getInt1Ty(), MinNumElts: 2);
3326 }
3327}
3328
3329constexpr unsigned SVEBitsPerBlock = 128;
3330
3331static llvm::ScalableVectorType *getSVEVectorForElementType(llvm::Type *EltTy) {
3332 unsigned NumElts = SVEBitsPerBlock / EltTy->getScalarSizeInBits();
3333 return llvm::ScalableVectorType::get(ElementType: EltTy, MinNumElts: NumElts);
3334}
3335
3336// Reinterpret the input predicate so that it can be used to correctly isolate
3337// the elements of the specified datatype.
3338Value *CodeGenFunction::EmitSVEPredicateCast(Value *Pred,
3339 llvm::ScalableVectorType *VTy) {
3340
3341 if (isa<TargetExtType>(Val: Pred->getType()) &&
3342 cast<TargetExtType>(Val: Pred->getType())->getName() == "aarch64.svcount")
3343 return Pred;
3344
3345 auto *RTy = llvm::VectorType::get(ElementType: IntegerType::get(C&: getLLVMContext(), NumBits: 1), Other: VTy);
3346 if (Pred->getType() == RTy)
3347 return Pred;
3348
3349 unsigned IntID;
3350 llvm::Type *IntrinsicTy;
3351 switch (VTy->getMinNumElements()) {
3352 default:
3353 llvm_unreachable("unsupported element count!");
3354 case 1:
3355 case 2:
3356 case 4:
3357 case 8:
3358 IntID = Intrinsic::aarch64_sve_convert_from_svbool;
3359 IntrinsicTy = RTy;
3360 break;
3361 case 16:
3362 IntID = Intrinsic::aarch64_sve_convert_to_svbool;
3363 IntrinsicTy = Pred->getType();
3364 break;
3365 }
3366
3367 Function *F = CGM.getIntrinsic(IID: IntID, Tys: IntrinsicTy);
3368 Value *C = Builder.CreateCall(Callee: F, Args: Pred);
3369 assert(C->getType() == RTy && "Unexpected return type!");
3370 return C;
3371}
3372
3373Value *CodeGenFunction::EmitSVEPredicateTupleCast(Value *PredTuple,
3374 llvm::StructType *Ty) {
3375 if (PredTuple->getType() == Ty)
3376 return PredTuple;
3377
3378 Value *Ret = llvm::PoisonValue::get(T: Ty);
3379 for (unsigned I = 0; I < Ty->getNumElements(); ++I) {
3380 Value *Pred = Builder.CreateExtractValue(Agg: PredTuple, Idxs: I);
3381 Pred = EmitSVEPredicateCast(
3382 Pred, VTy: cast<llvm::ScalableVectorType>(Val: Ty->getTypeAtIndex(N: I)));
3383 Ret = Builder.CreateInsertValue(Agg: Ret, Val: Pred, Idxs: I);
3384 }
3385
3386 return Ret;
3387}
3388
3389Value *CodeGenFunction::EmitSVEGatherLoad(const SVETypeFlags &TypeFlags,
3390 SmallVectorImpl<Value *> &Ops,
3391 unsigned IntID) {
3392 auto *ResultTy = getSVEType(TypeFlags);
3393 auto *OverloadedTy =
3394 llvm::ScalableVectorType::get(ElementType: SVEBuiltinMemEltTy(TypeFlags), SVTy: ResultTy);
3395 Function *F = CGM.getIntrinsic(IID: IntID, Tys: {OverloadedTy, Ops[1]->getType()});
3396
3397 // At the ACLE level there's only one predicate type, svbool_t, which is
3398 // mapped to <n x 16 x i1>. However, this might be incompatible with the
3399 // actual type being loaded. For example, when loading doubles (i64) the
3400 // predicate should be <n x 2 x i1> instead. At the IR level the type of
3401 // the predicate and the data being loaded must match. Cast to the type
3402 // expected by the intrinsic. The intrinsic itself should be defined in
3403 // a way than enforces relations between parameter types.
3404 Ops[0] = EmitSVEPredicateCast(
3405 Pred: Ops[0], VTy: cast<llvm::ScalableVectorType>(Val: F->getArg(i: 0)->getType()));
3406
3407 // Pass 0 when the offset is missing. This can only be applied when using
3408 // the "vector base" addressing mode for which ACLE allows no offset. The
3409 // corresponding LLVM IR always requires an offset.
3410 if (Ops.size() == 2) {
3411 assert(Ops[1]->getType()->isVectorTy() && "Scalar base requires an offset");
3412 Ops.push_back(Elt: ConstantInt::get(Ty: Int64Ty, V: 0));
3413 }
3414
3415 // For "vector base, scalar index" scale the index so that it becomes a
3416 // scalar offset.
3417 if (!TypeFlags.isByteIndexed() && Ops[1]->getType()->isVectorTy()) {
3418 unsigned BytesPerElt =
3419 OverloadedTy->getElementType()->getScalarSizeInBits() / 8;
3420 Ops[2] = Builder.CreateShl(LHS: Ops[2], RHS: Log2_32(Value: BytesPerElt));
3421 }
3422
3423 Value *Call = Builder.CreateCall(Callee: F, Args: Ops);
3424
3425 // The following sext/zext is only needed when ResultTy != OverloadedTy. In
3426 // other cases it's folded into a nop.
3427 return TypeFlags.isZExtReturn() ? Builder.CreateZExt(V: Call, DestTy: ResultTy)
3428 : Builder.CreateSExt(V: Call, DestTy: ResultTy);
3429}
3430
3431Value *CodeGenFunction::EmitSVEScatterStore(const SVETypeFlags &TypeFlags,
3432 SmallVectorImpl<Value *> &Ops,
3433 unsigned IntID) {
3434 auto *SrcDataTy = getSVEType(TypeFlags);
3435 auto *OverloadedTy =
3436 llvm::ScalableVectorType::get(ElementType: SVEBuiltinMemEltTy(TypeFlags), SVTy: SrcDataTy);
3437
3438 // In ACLE the source data is passed in the last argument, whereas in LLVM IR
3439 // it's the first argument. Move it accordingly.
3440 Ops.insert(I: Ops.begin(), Elt: Ops.pop_back_val());
3441
3442 Function *F = CGM.getIntrinsic(IID: IntID, Tys: {OverloadedTy, Ops[2]->getType()});
3443
3444 // Pass 0 when the offset is missing. This can only be applied when using
3445 // the "vector base" addressing mode for which ACLE allows no offset. The
3446 // corresponding LLVM IR always requires an offset.
3447 if (Ops.size() == 3) {
3448 assert(Ops[1]->getType()->isVectorTy() && "Scalar base requires an offset");
3449 Ops.push_back(Elt: ConstantInt::get(Ty: Int64Ty, V: 0));
3450 }
3451
3452 // Truncation is needed when SrcDataTy != OverloadedTy. In other cases it's
3453 // folded into a nop.
3454 Ops[0] = Builder.CreateTrunc(V: Ops[0], DestTy: OverloadedTy);
3455
3456 // At the ACLE level there's only one predicate type, svbool_t, which is
3457 // mapped to <n x 16 x i1>. However, this might be incompatible with the
3458 // actual type being stored. For example, when storing doubles (i64) the
3459 // predicated should be <n x 2 x i1> instead. At the IR level the type of
3460 // the predicate and the data being stored must match. Cast to the type
3461 // expected by the intrinsic. The intrinsic itself should be defined in
3462 // a way that enforces relations between parameter types.
3463 Ops[1] = EmitSVEPredicateCast(
3464 Pred: Ops[1], VTy: cast<llvm::ScalableVectorType>(Val: F->getArg(i: 1)->getType()));
3465
3466 // For "vector base, scalar index" scale the index so that it becomes a
3467 // scalar offset.
3468 if (!TypeFlags.isByteIndexed() && Ops[2]->getType()->isVectorTy()) {
3469 unsigned BytesPerElt =
3470 OverloadedTy->getElementType()->getScalarSizeInBits() / 8;
3471 Ops[3] = Builder.CreateShl(LHS: Ops[3], RHS: Log2_32(Value: BytesPerElt));
3472 }
3473
3474 return Builder.CreateCall(Callee: F, Args: Ops);
3475}
3476
3477Value *CodeGenFunction::EmitSVEGatherPrefetch(const SVETypeFlags &TypeFlags,
3478 SmallVectorImpl<Value *> &Ops,
3479 unsigned IntID) {
3480 // The gather prefetches are overloaded on the vector input - this can either
3481 // be the vector of base addresses or vector of offsets.
3482 auto *OverloadedTy = dyn_cast<llvm::ScalableVectorType>(Val: Ops[1]->getType());
3483 if (!OverloadedTy)
3484 OverloadedTy = cast<llvm::ScalableVectorType>(Val: Ops[2]->getType());
3485
3486 // Cast the predicate from svbool_t to the right number of elements.
3487 Ops[0] = EmitSVEPredicateCast(Pred: Ops[0], VTy: OverloadedTy);
3488
3489 // vector + imm addressing modes
3490 if (Ops[1]->getType()->isVectorTy()) {
3491 if (Ops.size() == 3) {
3492 // Pass 0 for 'vector+imm' when the index is omitted.
3493 Ops.push_back(Elt: ConstantInt::get(Ty: Int64Ty, V: 0));
3494
3495 // The sv_prfop is the last operand in the builtin and IR intrinsic.
3496 std::swap(a&: Ops[2], b&: Ops[3]);
3497 } else {
3498 // Index needs to be passed as scaled offset.
3499 llvm::Type *MemEltTy = SVEBuiltinMemEltTy(TypeFlags);
3500 unsigned BytesPerElt = MemEltTy->getPrimitiveSizeInBits() / 8;
3501 if (BytesPerElt > 1)
3502 Ops[2] = Builder.CreateShl(LHS: Ops[2], RHS: Log2_32(Value: BytesPerElt));
3503 }
3504
3505 Function *F = CGM.getIntrinsic(IID: IntID, Tys: OverloadedTy);
3506 return Builder.CreateCall(Callee: F, Args: Ops);
3507 }
3508
3509 Function *F = CGM.getIntrinsic(IID: IntID, Tys: {Ops[1]->getType(), OverloadedTy});
3510 return Builder.CreateCall(Callee: F, Args: Ops);
3511}
3512
3513Value *CodeGenFunction::EmitSVEStructLoad(const SVETypeFlags &TypeFlags,
3514 SmallVectorImpl<Value*> &Ops,
3515 unsigned IntID) {
3516 llvm::ScalableVectorType *VTy = getSVEType(TypeFlags);
3517 Value *Predicate = EmitSVEPredicateCast(Pred: Ops[0], VTy);
3518 Value *BasePtr = Ops[1];
3519
3520 // Does the load have an offset?
3521 if (Ops.size() > 2)
3522 BasePtr = Builder.CreateGEP(Ty: VTy, Ptr: BasePtr, IdxList: Ops[2]);
3523
3524 Function *F = CGM.getIntrinsic(IID: IntID, Tys: {VTy, BasePtr->getType()});
3525 return Builder.CreateCall(Callee: F, Args: {Predicate, BasePtr});
3526}
3527
3528Value *CodeGenFunction::EmitSVEStructStore(const SVETypeFlags &TypeFlags,
3529 SmallVectorImpl<Value*> &Ops,
3530 unsigned IntID) {
3531 llvm::ScalableVectorType *VTy = getSVEType(TypeFlags);
3532
3533 unsigned N;
3534 switch (IntID) {
3535 case Intrinsic::aarch64_sve_st2:
3536 case Intrinsic::aarch64_sve_st1_pn_x2:
3537 case Intrinsic::aarch64_sve_stnt1_pn_x2:
3538 case Intrinsic::aarch64_sve_st2q:
3539 N = 2;
3540 break;
3541 case Intrinsic::aarch64_sve_st3:
3542 case Intrinsic::aarch64_sve_st3q:
3543 N = 3;
3544 break;
3545 case Intrinsic::aarch64_sve_st4:
3546 case Intrinsic::aarch64_sve_st1_pn_x4:
3547 case Intrinsic::aarch64_sve_stnt1_pn_x4:
3548 case Intrinsic::aarch64_sve_st4q:
3549 N = 4;
3550 break;
3551 default:
3552 llvm_unreachable("unknown intrinsic!");
3553 }
3554
3555 Value *Predicate = EmitSVEPredicateCast(Pred: Ops[0], VTy);
3556 Value *BasePtr = Ops[1];
3557
3558 // Does the store have an offset?
3559 if (Ops.size() > (2 + N))
3560 BasePtr = Builder.CreateGEP(Ty: VTy, Ptr: BasePtr, IdxList: Ops[2]);
3561
3562 // The llvm.aarch64.sve.st2/3/4 intrinsics take legal part vectors, so we
3563 // need to break up the tuple vector.
3564 SmallVector<llvm::Value*, 5> Operands;
3565 for (unsigned I = Ops.size() - N; I < Ops.size(); ++I)
3566 Operands.push_back(Elt: Ops[I]);
3567 Operands.append(IL: {Predicate, BasePtr});
3568 Function *F = CGM.getIntrinsic(IID: IntID, Tys: {VTy, BasePtr->getType()});
3569
3570 return Builder.CreateCall(Callee: F, Args: Operands);
3571}
3572
3573// SVE2's svpmullb and svpmullt builtins are similar to the svpmullb_pair and
3574// svpmullt_pair intrinsics, with the exception that their results are bitcast
3575// to a wider type.
3576Value *CodeGenFunction::EmitSVEPMull(const SVETypeFlags &TypeFlags,
3577 SmallVectorImpl<Value *> &Ops,
3578 unsigned BuiltinID) {
3579 // Splat scalar operand to vector (intrinsics with _n infix)
3580 if (TypeFlags.hasSplatOperand()) {
3581 unsigned OpNo = TypeFlags.getSplatOperand();
3582 Ops[OpNo] = EmitSVEDupX(Scalar: Ops[OpNo]);
3583 }
3584
3585 // The pair-wise function has a narrower overloaded type.
3586 Function *F = CGM.getIntrinsic(IID: BuiltinID, Tys: Ops[0]->getType());
3587 Value *Call = Builder.CreateCall(Callee: F, Args: {Ops[0], Ops[1]});
3588
3589 // Now bitcast to the wider result type.
3590 llvm::ScalableVectorType *Ty = getSVEType(TypeFlags);
3591 return EmitSVEReinterpret(Val: Call, Ty);
3592}
3593
3594Value *CodeGenFunction::EmitSVEMovl(const SVETypeFlags &TypeFlags,
3595 ArrayRef<Value *> Ops, unsigned BuiltinID) {
3596 llvm::Type *OverloadedTy = getSVEType(TypeFlags);
3597 Function *F = CGM.getIntrinsic(IID: BuiltinID, Tys: OverloadedTy);
3598 return Builder.CreateCall(Callee: F, Args: {Ops[0], Builder.getInt32(C: 0)});
3599}
3600
3601Value *CodeGenFunction::EmitSVEPrefetchLoad(const SVETypeFlags &TypeFlags,
3602 SmallVectorImpl<Value *> &Ops,
3603 unsigned BuiltinID) {
3604 auto *MemEltTy = SVEBuiltinMemEltTy(TypeFlags);
3605 auto *VectorTy = getSVEVectorForElementType(EltTy: MemEltTy);
3606 auto *MemoryTy = llvm::ScalableVectorType::get(ElementType: MemEltTy, SVTy: VectorTy);
3607
3608 Value *Predicate = EmitSVEPredicateCast(Pred: Ops[0], VTy: MemoryTy);
3609 Value *BasePtr = Ops[1];
3610
3611 // Implement the index operand if not omitted.
3612 if (Ops.size() > 3)
3613 BasePtr = Builder.CreateGEP(Ty: MemoryTy, Ptr: BasePtr, IdxList: Ops[2]);
3614
3615 Value *PrfOp = Ops.back();
3616
3617 llvm::Type *Tys[2] = {Predicate->getType(), BasePtr->getType()};
3618 Function *F = CGM.getIntrinsic(IID: BuiltinID, Tys);
3619 return Builder.CreateCall(Callee: F, Args: {Predicate, BasePtr, PrfOp});
3620}
3621
3622Value *CodeGenFunction::EmitSVEMaskedLoad(const CallExpr *E,
3623 llvm::Type *ReturnTy,
3624 SmallVectorImpl<Value *> &Ops,
3625 unsigned IntrinsicID,
3626 bool IsZExtReturn) {
3627 QualType LangPTy = E->getArg(Arg: 1)->getType();
3628 llvm::Type *MemEltTy = CGM.getTypes().ConvertType(
3629 T: LangPTy->castAs<PointerType>()->getPointeeType());
3630
3631 // Mfloat8 types is stored as a vector, so extra work
3632 // to extract sclar element type is necessary.
3633 if (MemEltTy->isVectorTy()) {
3634 assert(MemEltTy == FixedVectorType::get(Int8Ty, 1) &&
3635 "Only <1 x i8> expected");
3636 MemEltTy = cast<llvm::VectorType>(Val: MemEltTy)->getElementType();
3637 }
3638
3639 // The vector type that is returned may be different from the
3640 // eventual type loaded from memory.
3641 auto VectorTy = cast<llvm::ScalableVectorType>(Val: ReturnTy);
3642 llvm::ScalableVectorType *MemoryTy = nullptr;
3643 llvm::ScalableVectorType *PredTy = nullptr;
3644 bool IsQuadLoad = false;
3645 switch (IntrinsicID) {
3646 case Intrinsic::aarch64_sve_ld1uwq:
3647 case Intrinsic::aarch64_sve_ld1udq:
3648 MemoryTy = llvm::ScalableVectorType::get(ElementType: MemEltTy, MinNumElts: 1);
3649 PredTy = llvm::ScalableVectorType::get(
3650 ElementType: llvm::Type::getInt1Ty(C&: getLLVMContext()), MinNumElts: 1);
3651 IsQuadLoad = true;
3652 break;
3653 default:
3654 MemoryTy = llvm::ScalableVectorType::get(ElementType: MemEltTy, SVTy: VectorTy);
3655 PredTy = MemoryTy;
3656 break;
3657 }
3658
3659 Value *Predicate = EmitSVEPredicateCast(Pred: Ops[0], VTy: PredTy);
3660 Value *BasePtr = Ops[1];
3661
3662 // Does the load have an offset?
3663 if (Ops.size() > 2)
3664 BasePtr = Builder.CreateGEP(Ty: MemoryTy, Ptr: BasePtr, IdxList: Ops[2]);
3665
3666 llvm::Type *Tys[2] = {IsQuadLoad ? VectorTy : MemoryTy, BasePtr->getType()};
3667 Function *F = CGM.getIntrinsic(IID: IntrinsicID, Tys);
3668 auto *Load = Builder.CreateCall(Callee: F, Args: {Predicate, BasePtr});
3669 auto TBAAInfo = CGM.getTBAAAccessInfo(AccessType: LangPTy->getPointeeType());
3670 CGM.DecorateInstructionWithTBAA(Inst: Load, TBAAInfo);
3671
3672 if (IsQuadLoad)
3673 return Load;
3674
3675 return IsZExtReturn ? Builder.CreateZExt(V: Load, DestTy: VectorTy)
3676 : Builder.CreateSExt(V: Load, DestTy: VectorTy);
3677}
3678
3679Value *CodeGenFunction::EmitSVEMaskedStore(const CallExpr *E,
3680 SmallVectorImpl<Value *> &Ops,
3681 unsigned IntrinsicID) {
3682 QualType LangPTy = E->getArg(Arg: 1)->getType();
3683 llvm::Type *MemEltTy = CGM.getTypes().ConvertType(
3684 T: LangPTy->castAs<PointerType>()->getPointeeType());
3685
3686 // Mfloat8 types is stored as a vector, so extra work
3687 // to extract sclar element type is necessary.
3688 if (MemEltTy->isVectorTy()) {
3689 assert(MemEltTy == FixedVectorType::get(Int8Ty, 1) &&
3690 "Only <1 x i8> expected");
3691 MemEltTy = cast<llvm::VectorType>(Val: MemEltTy)->getElementType();
3692 }
3693
3694 // The vector type that is stored may be different from the
3695 // eventual type stored to memory.
3696 auto VectorTy = cast<llvm::ScalableVectorType>(Val: Ops.back()->getType());
3697 auto MemoryTy = llvm::ScalableVectorType::get(ElementType: MemEltTy, SVTy: VectorTy);
3698
3699 auto PredTy = MemoryTy;
3700 auto AddrMemoryTy = MemoryTy;
3701 bool IsQuadStore = false;
3702
3703 switch (IntrinsicID) {
3704 case Intrinsic::aarch64_sve_st1wq:
3705 case Intrinsic::aarch64_sve_st1dq:
3706 AddrMemoryTy = llvm::ScalableVectorType::get(ElementType: MemEltTy, MinNumElts: 1);
3707 PredTy =
3708 llvm::ScalableVectorType::get(ElementType: IntegerType::get(C&: getLLVMContext(), NumBits: 1), MinNumElts: 1);
3709 IsQuadStore = true;
3710 break;
3711 default:
3712 break;
3713 }
3714 Value *Predicate = EmitSVEPredicateCast(Pred: Ops[0], VTy: PredTy);
3715 Value *BasePtr = Ops[1];
3716
3717 // Does the store have an offset?
3718 if (Ops.size() == 4)
3719 BasePtr = Builder.CreateGEP(Ty: AddrMemoryTy, Ptr: BasePtr, IdxList: Ops[2]);
3720
3721 // Last value is always the data
3722 Value *Val =
3723 IsQuadStore ? Ops.back() : Builder.CreateTrunc(V: Ops.back(), DestTy: MemoryTy);
3724
3725 llvm::Type *Tys[2] = {IsQuadStore ? VectorTy : MemoryTy, BasePtr->getType()};
3726 Function *F = CGM.getIntrinsic(IID: IntrinsicID, Tys);
3727 auto *Store = Builder.CreateCall(Callee: F, Args: {Val, Predicate, BasePtr});
3728 auto TBAAInfo = CGM.getTBAAAccessInfo(AccessType: LangPTy->getPointeeType());
3729 CGM.DecorateInstructionWithTBAA(Inst: Store, TBAAInfo);
3730 return Store;
3731}
3732
3733Value *CodeGenFunction::EmitSMELd1St1(const SVETypeFlags &TypeFlags,
3734 SmallVectorImpl<Value *> &Ops,
3735 unsigned IntID) {
3736 Ops[2] = EmitSVEPredicateCast(
3737 Pred: Ops[2], VTy: getSVEVectorForElementType(EltTy: SVEBuiltinMemEltTy(TypeFlags)));
3738
3739 SmallVector<Value *> NewOps;
3740 NewOps.push_back(Elt: Ops[2]);
3741
3742 llvm::Value *BasePtr = Ops[3];
3743 llvm::Value *RealSlice = Ops[1];
3744 // If the intrinsic contains the vnum parameter, multiply it with the vector
3745 // size in bytes.
3746 if (Ops.size() == 5) {
3747 Function *StreamingVectorLength =
3748 CGM.getIntrinsic(IID: Intrinsic::aarch64_sme_cntsd);
3749 llvm::Value *StreamingVectorLengthCall =
3750 Builder.CreateMul(LHS: Builder.CreateCall(Callee: StreamingVectorLength),
3751 RHS: llvm::ConstantInt::get(Ty: Int64Ty, V: 8), Name: "svl",
3752 /* HasNUW */ true, /* HasNSW */ true);
3753 llvm::Value *Mulvl =
3754 Builder.CreateMul(LHS: StreamingVectorLengthCall, RHS: Ops[4], Name: "mulvl");
3755 // The type of the ptr parameter is void *, so use Int8Ty here.
3756 BasePtr = Builder.CreateGEP(Ty: Int8Ty, Ptr: Ops[3], IdxList: Mulvl);
3757 RealSlice = Builder.CreateZExt(V: RealSlice, DestTy: Int64Ty);
3758 RealSlice = Builder.CreateAdd(LHS: RealSlice, RHS: Ops[4]);
3759 RealSlice = Builder.CreateTrunc(V: RealSlice, DestTy: Int32Ty);
3760 }
3761 NewOps.push_back(Elt: BasePtr);
3762 NewOps.push_back(Elt: Ops[0]);
3763 NewOps.push_back(Elt: RealSlice);
3764 Function *F = CGM.getIntrinsic(IID: IntID, Tys: BasePtr->getType());
3765 return Builder.CreateCall(Callee: F, Args: NewOps);
3766}
3767
3768Value *CodeGenFunction::EmitSMEReadWrite(const SVETypeFlags &TypeFlags,
3769 SmallVectorImpl<Value *> &Ops,
3770 unsigned IntID) {
3771 auto *VecTy = getSVEType(TypeFlags);
3772 Function *F = CGM.getIntrinsic(IID: IntID, Tys: VecTy);
3773 if (TypeFlags.isReadZA())
3774 Ops[1] = EmitSVEPredicateCast(Pred: Ops[1], VTy: VecTy);
3775 else if (TypeFlags.isWriteZA())
3776 Ops[2] = EmitSVEPredicateCast(Pred: Ops[2], VTy: VecTy);
3777 return Builder.CreateCall(Callee: F, Args: Ops);
3778}
3779
3780Value *CodeGenFunction::EmitSMEZero(const SVETypeFlags &TypeFlags,
3781 SmallVectorImpl<Value *> &Ops,
3782 unsigned IntID) {
3783 // svzero_za() intrinsic zeros the entire za tile and has no paramters.
3784 if (Ops.size() == 0)
3785 Ops.push_back(Elt: llvm::ConstantInt::get(Ty: Int32Ty, V: 255));
3786 Function *F = CGM.getIntrinsic(IID: IntID, Tys: {});
3787 return Builder.CreateCall(Callee: F, Args: Ops);
3788}
3789
3790Value *CodeGenFunction::EmitSMELdrStr(const SVETypeFlags &TypeFlags,
3791 SmallVectorImpl<Value *> &Ops,
3792 unsigned IntID) {
3793 if (Ops.size() == 2)
3794 Ops.push_back(Elt: Builder.getInt32(C: 0));
3795 else
3796 Ops[2] = Builder.CreateIntCast(V: Ops[2], DestTy: Int32Ty, isSigned: true);
3797 Function *F = CGM.getIntrinsic(IID: IntID, Tys: Ops[1]->getType());
3798 return Builder.CreateCall(Callee: F, Args: Ops);
3799}
3800
3801// Limit the usage of scalable llvm IR generated by the ACLE by using the
3802// sve dup.x intrinsic instead of IRBuilder::CreateVectorSplat.
3803Value *CodeGenFunction::EmitSVEDupX(Value *Scalar, llvm::Type *Ty) {
3804 return Builder.CreateVectorSplat(
3805 EC: cast<llvm::VectorType>(Val: Ty)->getElementCount(), V: Scalar);
3806}
3807
3808Value *CodeGenFunction::EmitSVEDupX(Value *Scalar) {
3809 if (auto *Ty = Scalar->getType(); Ty->isVectorTy()) {
3810#ifndef NDEBUG
3811 auto *VecTy = cast<llvm::VectorType>(Ty);
3812 ElementCount EC = VecTy->getElementCount();
3813 assert(EC.isScalar() && VecTy->getElementType() == Int8Ty &&
3814 "Only <1 x i8> expected");
3815#endif
3816 Scalar = Builder.CreateExtractElement(Vec: Scalar, Idx: uint64_t(0));
3817 }
3818 return EmitSVEDupX(Scalar, Ty: getSVEVectorForElementType(EltTy: Scalar->getType()));
3819}
3820
3821Value *CodeGenFunction::EmitSVEReinterpret(Value *Val, llvm::Type *Ty) {
3822 // FIXME: For big endian this needs an additional REV, or needs a separate
3823 // intrinsic that is code-generated as a no-op, because the LLVM bitcast
3824 // instruction is defined as 'bitwise' equivalent from memory point of
3825 // view (when storing/reloading), whereas the svreinterpret builtin
3826 // implements bitwise equivalent cast from register point of view.
3827 // LLVM CodeGen for a bitcast must add an explicit REV for big-endian.
3828
3829 if (auto *StructTy = dyn_cast<StructType>(Val: Ty)) {
3830 Value *Tuple = llvm::PoisonValue::get(T: Ty);
3831
3832 for (unsigned I = 0; I < StructTy->getNumElements(); ++I) {
3833 Value *In = Builder.CreateExtractValue(Agg: Val, Idxs: I);
3834 Value *Out = Builder.CreateBitCast(V: In, DestTy: StructTy->getTypeAtIndex(N: I));
3835 Tuple = Builder.CreateInsertValue(Agg: Tuple, Val: Out, Idxs: I);
3836 }
3837
3838 return Tuple;
3839 }
3840
3841 return Builder.CreateBitCast(V: Val, DestTy: Ty);
3842}
3843
3844static void InsertExplicitZeroOperand(CGBuilderTy &Builder, llvm::Type *Ty,
3845 SmallVectorImpl<Value *> &Ops) {
3846 auto *SplatZero = Constant::getNullValue(Ty);
3847 Ops.insert(I: Ops.begin(), Elt: SplatZero);
3848}
3849
3850static void InsertExplicitUndefOperand(CGBuilderTy &Builder, llvm::Type *Ty,
3851 SmallVectorImpl<Value *> &Ops) {
3852 auto *SplatUndef = UndefValue::get(T: Ty);
3853 Ops.insert(I: Ops.begin(), Elt: SplatUndef);
3854}
3855
3856SmallVector<llvm::Type *, 2>
3857CodeGenFunction::getSVEOverloadTypes(const SVETypeFlags &TypeFlags,
3858 llvm::Type *ResultType,
3859 ArrayRef<Value *> Ops) {
3860 if (TypeFlags.isOverloadNone())
3861 return {};
3862
3863 llvm::Type *DefaultType = getSVEType(TypeFlags);
3864
3865 if (TypeFlags.isOverloadWhileOrMultiVecCvt())
3866 return {DefaultType, Ops[1]->getType()};
3867
3868 if (TypeFlags.isOverloadWhileRW())
3869 return {getSVEPredType(TypeFlags), Ops[0]->getType()};
3870
3871 if (TypeFlags.isOverloadDefaultAndOp0())
3872 return {DefaultType, Ops[0]->getType()};
3873
3874 if (TypeFlags.isOverloadFirstandLast())
3875 return {Ops[0]->getType(), Ops.back()->getType()};
3876
3877 if (TypeFlags.isReductionQV())
3878 return {ResultType, Ops[1]->getType()};
3879
3880 assert(TypeFlags.isOverloadDefault() && "Unexpected value for overloads");
3881 return {DefaultType};
3882}
3883
3884Value *CodeGenFunction::EmitSVETupleSetOrGet(const SVETypeFlags &TypeFlags,
3885 ArrayRef<Value *> Ops) {
3886 assert((TypeFlags.isTupleSet() || TypeFlags.isTupleGet()) &&
3887 "Expects TypleFlags.isTupleSet() or TypeFlags.isTupleGet()");
3888 unsigned Idx = cast<ConstantInt>(Val: Ops[1])->getZExtValue();
3889
3890 if (TypeFlags.isTupleSet())
3891 return Builder.CreateInsertValue(Agg: Ops[0], Val: Ops[2], Idxs: Idx);
3892 return Builder.CreateExtractValue(Agg: Ops[0], Idxs: Idx);
3893}
3894
3895Value *CodeGenFunction::EmitSVETupleCreate(const SVETypeFlags &TypeFlags,
3896 llvm::Type *Ty,
3897 ArrayRef<Value *> Ops) {
3898 assert(TypeFlags.isTupleCreate() && "Expects TypleFlag isTupleCreate");
3899
3900 Value *Tuple = llvm::PoisonValue::get(T: Ty);
3901 for (unsigned Idx = 0; Idx < Ops.size(); Idx++)
3902 Tuple = Builder.CreateInsertValue(Agg: Tuple, Val: Ops[Idx], Idxs: Idx);
3903
3904 return Tuple;
3905}
3906
3907void CodeGenFunction::GetAArch64SVEProcessedOperands(
3908 unsigned BuiltinID, const CallExpr *E, SmallVectorImpl<Value *> &Ops,
3909 SVETypeFlags TypeFlags) {
3910 // Find out if any arguments are required to be integer constant expressions.
3911 unsigned ICEArguments = 0;
3912 ASTContext::GetBuiltinTypeError Error;
3913 getContext().GetBuiltinType(ID: BuiltinID, Error, IntegerConstantArgs: &ICEArguments);
3914 assert(Error == ASTContext::GE_None && "Should not codegen an error");
3915
3916 // Tuple set/get only requires one insert/extract vector, which is
3917 // created by EmitSVETupleSetOrGet.
3918 bool IsTupleGetOrSet = TypeFlags.isTupleSet() || TypeFlags.isTupleGet();
3919
3920 for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) {
3921 bool IsICE = ICEArguments & (1 << i);
3922 Value *Arg = EmitScalarExpr(E: E->getArg(Arg: i));
3923
3924 if (IsICE) {
3925 // If this is required to be a constant, constant fold it so that we know
3926 // that the generated intrinsic gets a ConstantInt.
3927 std::optional<llvm::APSInt> Result =
3928 E->getArg(Arg: i)->getIntegerConstantExpr(Ctx: getContext());
3929 assert(Result && "Expected argument to be a constant");
3930
3931 // Immediates for SVE llvm intrinsics are always 32bit. We can safely
3932 // truncate because the immediate has been range checked and no valid
3933 // immediate requires more than a handful of bits.
3934 *Result = Result->extOrTrunc(width: 32);
3935 Ops.push_back(Elt: llvm::ConstantInt::get(Context&: getLLVMContext(), V: *Result));
3936 continue;
3937 }
3938
3939 if (isa<StructType>(Val: Arg->getType()) && !IsTupleGetOrSet) {
3940 for (unsigned I = 0; I < Arg->getType()->getStructNumElements(); ++I)
3941 Ops.push_back(Elt: Builder.CreateExtractValue(Agg: Arg, Idxs: I));
3942
3943 continue;
3944 }
3945
3946 Ops.push_back(Elt: Arg);
3947 }
3948}
3949
3950Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
3951 const CallExpr *E) {
3952 llvm::Type *Ty = ConvertType(T: E->getType());
3953 if (BuiltinID >= SVE::BI__builtin_sve_reinterpret_s8_s8 &&
3954 BuiltinID <= SVE::BI__builtin_sve_reinterpret_f64_f64_x4) {
3955 Value *Val = EmitScalarExpr(E: E->getArg(Arg: 0));
3956 return EmitSVEReinterpret(Val, Ty);
3957 }
3958
3959 auto *Builtin =
3960 findARMVectorIntrinsicInMap(IntrinsicMap: ArrayRef(AArch64SVEIntrinsicMap), BuiltinID,
3961 MapProvenSorted&: AArch64SVEIntrinsicsProvenSorted);
3962
3963 llvm::SmallVector<Value *, 4> Ops;
3964 SVETypeFlags TypeFlags(Builtin->TypeModifier);
3965 GetAArch64SVEProcessedOperands(BuiltinID, E, Ops, TypeFlags);
3966
3967 if (TypeFlags.isLoad())
3968 return EmitSVEMaskedLoad(E, ReturnTy: Ty, Ops, IntrinsicID: Builtin->LLVMIntrinsic,
3969 IsZExtReturn: TypeFlags.isZExtReturn());
3970 if (TypeFlags.isStore())
3971 return EmitSVEMaskedStore(E, Ops, IntrinsicID: Builtin->LLVMIntrinsic);
3972 if (TypeFlags.isGatherLoad())
3973 return EmitSVEGatherLoad(TypeFlags, Ops, IntID: Builtin->LLVMIntrinsic);
3974 if (TypeFlags.isScatterStore())
3975 return EmitSVEScatterStore(TypeFlags, Ops, IntID: Builtin->LLVMIntrinsic);
3976 if (TypeFlags.isPrefetch())
3977 return EmitSVEPrefetchLoad(TypeFlags, Ops, BuiltinID: Builtin->LLVMIntrinsic);
3978 if (TypeFlags.isGatherPrefetch())
3979 return EmitSVEGatherPrefetch(TypeFlags, Ops, IntID: Builtin->LLVMIntrinsic);
3980 if (TypeFlags.isStructLoad())
3981 return EmitSVEStructLoad(TypeFlags, Ops, IntID: Builtin->LLVMIntrinsic);
3982 if (TypeFlags.isStructStore())
3983 return EmitSVEStructStore(TypeFlags, Ops, IntID: Builtin->LLVMIntrinsic);
3984 if (TypeFlags.isTupleSet() || TypeFlags.isTupleGet())
3985 return EmitSVETupleSetOrGet(TypeFlags, Ops);
3986 if (TypeFlags.isTupleCreate())
3987 return EmitSVETupleCreate(TypeFlags, Ty, Ops);
3988 if (TypeFlags.isUndef())
3989 return UndefValue::get(T: Ty);
3990
3991 // Handle built-ins for which there is a corresponding LLVM Intrinsic.
3992 // -------------------------------------------------------------------
3993 if (Builtin->LLVMIntrinsic != 0) {
3994 // Emit set FPMR for intrinsics that require it
3995 if (TypeFlags.setsFPMR())
3996 Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_set_fpmr),
3997 Args: Ops.pop_back_val());
3998 if (TypeFlags.getMergeType() == SVETypeFlags::MergeZeroExp)
3999 InsertExplicitZeroOperand(Builder, Ty, Ops);
4000
4001 if (TypeFlags.getMergeType() == SVETypeFlags::MergeAnyExp)
4002 InsertExplicitUndefOperand(Builder, Ty, Ops);
4003
4004 // Some ACLE builtins leave out the argument to specify the predicate
4005 // pattern, which is expected to be expanded to an SV_ALL pattern.
4006 if (TypeFlags.isAppendSVALL())
4007 Ops.push_back(Elt: Builder.getInt32(/*SV_ALL*/ C: 31));
4008 if (TypeFlags.isInsertOp1SVALL())
4009 Ops.insert(I: &Ops[1], Elt: Builder.getInt32(/*SV_ALL*/ C: 31));
4010
4011 // Predicates must match the main datatype.
4012 for (Value *&Op : Ops)
4013 if (auto PredTy = dyn_cast<llvm::VectorType>(Val: Op->getType()))
4014 if (PredTy->getElementType()->isIntegerTy(BitWidth: 1))
4015 Op = EmitSVEPredicateCast(Pred: Op, VTy: getSVEType(TypeFlags));
4016
4017 // Splat scalar operand to vector (intrinsics with _n infix)
4018 if (TypeFlags.hasSplatOperand()) {
4019 unsigned OpNo = TypeFlags.getSplatOperand();
4020 Ops[OpNo] = EmitSVEDupX(Scalar: Ops[OpNo]);
4021 }
4022
4023 if (TypeFlags.isReverseCompare())
4024 std::swap(a&: Ops[1], b&: Ops[2]);
4025 else if (TypeFlags.isReverseUSDOT())
4026 std::swap(a&: Ops[1], b&: Ops[2]);
4027 else if (TypeFlags.isReverseMergeAnyBinOp() &&
4028 TypeFlags.getMergeType() == SVETypeFlags::MergeAny)
4029 std::swap(a&: Ops[1], b&: Ops[2]);
4030 else if (TypeFlags.isReverseMergeAnyAccOp() &&
4031 TypeFlags.getMergeType() == SVETypeFlags::MergeAny)
4032 std::swap(a&: Ops[1], b&: Ops[3]);
4033
4034 // Predicated intrinsics with _z suffix need a select w/ zeroinitializer.
4035 if (TypeFlags.getMergeType() == SVETypeFlags::MergeZero) {
4036 llvm::Type *OpndTy = Ops[1]->getType();
4037 auto *SplatZero = Constant::getNullValue(Ty: OpndTy);
4038 Ops[1] = Builder.CreateSelect(C: Ops[0], True: Ops[1], False: SplatZero);
4039 }
4040
4041 Function *F = CGM.getIntrinsic(IID: Builtin->LLVMIntrinsic,
4042 Tys: getSVEOverloadTypes(TypeFlags, ResultType: Ty, Ops));
4043 Value *Call = Builder.CreateCall(Callee: F, Args: Ops);
4044
4045 if (Call->getType() == Ty)
4046 return Call;
4047
4048 // Predicate results must be converted to svbool_t.
4049 if (auto PredTy = dyn_cast<llvm::ScalableVectorType>(Val: Ty))
4050 return EmitSVEPredicateCast(Pred: Call, VTy: PredTy);
4051 if (auto PredTupleTy = dyn_cast<llvm::StructType>(Val: Ty))
4052 return EmitSVEPredicateTupleCast(PredTuple: Call, Ty: PredTupleTy);
4053
4054 llvm_unreachable("unsupported element count!");
4055 }
4056
4057 switch (BuiltinID) {
4058 default:
4059 return nullptr;
4060
4061 case SVE::BI__builtin_sve_svreinterpret_b: {
4062 Function *CastFromSVCountF =
4063 CGM.getIntrinsic(IID: Intrinsic::aarch64_sve_convert_from_svcount);
4064 return Builder.CreateCall(Callee: CastFromSVCountF, Args: Ops[0]);
4065 }
4066 case SVE::BI__builtin_sve_svreinterpret_c: {
4067 Function *CastToSVCountF =
4068 CGM.getIntrinsic(IID: Intrinsic::aarch64_sve_convert_to_svcount);
4069 return Builder.CreateCall(Callee: CastToSVCountF, Args: Ops[0]);
4070 }
4071
4072 case SVE::BI__builtin_sve_svpsel_lane_b8:
4073 case SVE::BI__builtin_sve_svpsel_lane_b16:
4074 case SVE::BI__builtin_sve_svpsel_lane_b32:
4075 case SVE::BI__builtin_sve_svpsel_lane_b64:
4076 case SVE::BI__builtin_sve_svpsel_lane_c8:
4077 case SVE::BI__builtin_sve_svpsel_lane_c16:
4078 case SVE::BI__builtin_sve_svpsel_lane_c32:
4079 case SVE::BI__builtin_sve_svpsel_lane_c64: {
4080 auto OverloadedTy = getSVEType(TypeFlags: SVETypeFlags(Builtin->TypeModifier));
4081 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_sve_psel,
4082 Tys: {Ops[0]->getType(), OverloadedTy});
4083 llvm::Value *Ops1 = EmitSVEPredicateCast(Pred: Ops[1], VTy: OverloadedTy);
4084 return Builder.CreateCall(Callee: F, Args: {Ops[0], Ops1, Ops[2]});
4085 }
4086 case SVE::BI__builtin_sve_svmov_b_z: {
4087 // svmov_b_z(pg, op) <=> svand_b_z(pg, op, op)
4088 SVETypeFlags TypeFlags(Builtin->TypeModifier);
4089 llvm::Type* OverloadedTy = getSVEType(TypeFlags);
4090 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_sve_and_z, Tys: OverloadedTy);
4091 return Builder.CreateCall(Callee: F, Args: {Ops[0], Ops[1], Ops[1]});
4092 }
4093
4094 case SVE::BI__builtin_sve_svnot_b_z: {
4095 // svnot_b_z(pg, op) <=> sveor_b_z(pg, op, pg)
4096 SVETypeFlags TypeFlags(Builtin->TypeModifier);
4097 llvm::Type* OverloadedTy = getSVEType(TypeFlags);
4098 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_sve_eor_z, Tys: OverloadedTy);
4099 return Builder.CreateCall(Callee: F, Args: {Ops[0], Ops[1], Ops[0]});
4100 }
4101
4102 case SVE::BI__builtin_sve_svmovlb_u16:
4103 case SVE::BI__builtin_sve_svmovlb_u32:
4104 case SVE::BI__builtin_sve_svmovlb_u64:
4105 return EmitSVEMovl(TypeFlags, Ops, BuiltinID: Intrinsic::aarch64_sve_ushllb);
4106
4107 case SVE::BI__builtin_sve_svmovlb_s16:
4108 case SVE::BI__builtin_sve_svmovlb_s32:
4109 case SVE::BI__builtin_sve_svmovlb_s64:
4110 return EmitSVEMovl(TypeFlags, Ops, BuiltinID: Intrinsic::aarch64_sve_sshllb);
4111
4112 case SVE::BI__builtin_sve_svmovlt_u16:
4113 case SVE::BI__builtin_sve_svmovlt_u32:
4114 case SVE::BI__builtin_sve_svmovlt_u64:
4115 return EmitSVEMovl(TypeFlags, Ops, BuiltinID: Intrinsic::aarch64_sve_ushllt);
4116
4117 case SVE::BI__builtin_sve_svmovlt_s16:
4118 case SVE::BI__builtin_sve_svmovlt_s32:
4119 case SVE::BI__builtin_sve_svmovlt_s64:
4120 return EmitSVEMovl(TypeFlags, Ops, BuiltinID: Intrinsic::aarch64_sve_sshllt);
4121
4122 case SVE::BI__builtin_sve_svpmullt_u16:
4123 case SVE::BI__builtin_sve_svpmullt_u64:
4124 case SVE::BI__builtin_sve_svpmullt_n_u16:
4125 case SVE::BI__builtin_sve_svpmullt_n_u64:
4126 return EmitSVEPMull(TypeFlags, Ops, BuiltinID: Intrinsic::aarch64_sve_pmullt_pair);
4127
4128 case SVE::BI__builtin_sve_svpmullb_u16:
4129 case SVE::BI__builtin_sve_svpmullb_u64:
4130 case SVE::BI__builtin_sve_svpmullb_n_u16:
4131 case SVE::BI__builtin_sve_svpmullb_n_u64:
4132 return EmitSVEPMull(TypeFlags, Ops, BuiltinID: Intrinsic::aarch64_sve_pmullb_pair);
4133
4134 case SVE::BI__builtin_sve_svdup_n_b8:
4135 case SVE::BI__builtin_sve_svdup_n_b16:
4136 case SVE::BI__builtin_sve_svdup_n_b32:
4137 case SVE::BI__builtin_sve_svdup_n_b64: {
4138 llvm::ScalableVectorType *OverloadedTy = getSVEType(TypeFlags);
4139 Value *Dup = EmitSVEDupX(Scalar: Ops[0], Ty: OverloadedTy);
4140 return EmitSVEPredicateCast(Pred: Dup, VTy: cast<llvm::ScalableVectorType>(Val: Ty));
4141 }
4142
4143 case SVE::BI__builtin_sve_svdupq_n_b8:
4144 case SVE::BI__builtin_sve_svdupq_n_b16:
4145 case SVE::BI__builtin_sve_svdupq_n_b32:
4146 case SVE::BI__builtin_sve_svdupq_n_b64:
4147 case SVE::BI__builtin_sve_svdupq_n_u8:
4148 case SVE::BI__builtin_sve_svdupq_n_s8:
4149 case SVE::BI__builtin_sve_svdupq_n_u64:
4150 case SVE::BI__builtin_sve_svdupq_n_f64:
4151 case SVE::BI__builtin_sve_svdupq_n_s64:
4152 case SVE::BI__builtin_sve_svdupq_n_u16:
4153 case SVE::BI__builtin_sve_svdupq_n_f16:
4154 case SVE::BI__builtin_sve_svdupq_n_bf16:
4155 case SVE::BI__builtin_sve_svdupq_n_s16:
4156 case SVE::BI__builtin_sve_svdupq_n_u32:
4157 case SVE::BI__builtin_sve_svdupq_n_f32:
4158 case SVE::BI__builtin_sve_svdupq_n_s32: {
4159 // These builtins are implemented by storing each element to an array and using
4160 // ld1rq to materialize a vector.
4161 unsigned NumOpnds = Ops.size();
4162
4163 bool IsBoolTy =
4164 cast<llvm::VectorType>(Val: Ty)->getElementType()->isIntegerTy(BitWidth: 1);
4165
4166 // For svdupq_n_b* the element type of is an integer of type 128/numelts,
4167 // so that the compare can use the width that is natural for the expected
4168 // number of predicate lanes.
4169 llvm::Type *EltTy = Ops[0]->getType();
4170 if (IsBoolTy)
4171 EltTy = IntegerType::get(C&: getLLVMContext(), NumBits: SVEBitsPerBlock / NumOpnds);
4172
4173 SmallVector<llvm::Value *, 16> VecOps;
4174 for (unsigned I = 0; I < NumOpnds; ++I)
4175 VecOps.push_back(Elt: Builder.CreateZExt(V: Ops[I], DestTy: EltTy));
4176 Value *Vec = BuildVector(Ops: VecOps);
4177
4178 llvm::Type *OverloadedTy = getSVEVectorForElementType(EltTy);
4179 Value *InsertSubVec = Builder.CreateInsertVector(
4180 DstType: OverloadedTy, SrcVec: PoisonValue::get(T: OverloadedTy), SubVec: Vec, Idx: uint64_t(0));
4181
4182 Function *F =
4183 CGM.getIntrinsic(IID: Intrinsic::aarch64_sve_dupq_lane, Tys: OverloadedTy);
4184 Value *DupQLane =
4185 Builder.CreateCall(Callee: F, Args: {InsertSubVec, Builder.getInt64(C: 0)});
4186
4187 if (!IsBoolTy)
4188 return DupQLane;
4189
4190 SVETypeFlags TypeFlags(Builtin->TypeModifier);
4191 Constant *Pred = ConstantInt::getTrue(Ty: getSVEPredType(TypeFlags));
4192
4193 // For svdupq_n_b* we need to add an additional 'cmpne' with '0'.
4194 F = CGM.getIntrinsic(IID: NumOpnds == 2 ? Intrinsic::aarch64_sve_cmpne
4195 : Intrinsic::aarch64_sve_cmpne_wide,
4196 Tys: OverloadedTy);
4197 Value *Call = Builder.CreateCall(
4198 Callee: F, Args: {Pred, DupQLane, EmitSVEDupX(Scalar: Builder.getInt64(C: 0))});
4199 return EmitSVEPredicateCast(Pred: Call, VTy: cast<llvm::ScalableVectorType>(Val: Ty));
4200 }
4201
4202 case SVE::BI__builtin_sve_svpfalse_b:
4203 return ConstantInt::getFalse(Ty);
4204
4205 case SVE::BI__builtin_sve_svpfalse_c:
4206 return Constant::getNullValue(Ty);
4207
4208 case SVE::BI__builtin_sve_svlen_bf16:
4209 case SVE::BI__builtin_sve_svlen_f16:
4210 case SVE::BI__builtin_sve_svlen_f32:
4211 case SVE::BI__builtin_sve_svlen_f64:
4212 case SVE::BI__builtin_sve_svlen_s8:
4213 case SVE::BI__builtin_sve_svlen_s16:
4214 case SVE::BI__builtin_sve_svlen_s32:
4215 case SVE::BI__builtin_sve_svlen_s64:
4216 case SVE::BI__builtin_sve_svlen_u8:
4217 case SVE::BI__builtin_sve_svlen_u16:
4218 case SVE::BI__builtin_sve_svlen_u32:
4219 case SVE::BI__builtin_sve_svlen_u64: {
4220 SVETypeFlags TF(Builtin->TypeModifier);
4221 return Builder.CreateElementCount(Ty, EC: getSVEType(TypeFlags: TF)->getElementCount());
4222 }
4223
4224 case SVE::BI__builtin_sve_svtbl2_u8:
4225 case SVE::BI__builtin_sve_svtbl2_s8:
4226 case SVE::BI__builtin_sve_svtbl2_u16:
4227 case SVE::BI__builtin_sve_svtbl2_s16:
4228 case SVE::BI__builtin_sve_svtbl2_u32:
4229 case SVE::BI__builtin_sve_svtbl2_s32:
4230 case SVE::BI__builtin_sve_svtbl2_u64:
4231 case SVE::BI__builtin_sve_svtbl2_s64:
4232 case SVE::BI__builtin_sve_svtbl2_f16:
4233 case SVE::BI__builtin_sve_svtbl2_bf16:
4234 case SVE::BI__builtin_sve_svtbl2_f32:
4235 case SVE::BI__builtin_sve_svtbl2_f64: {
4236 SVETypeFlags TF(Builtin->TypeModifier);
4237 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_sve_tbl2, Tys: getSVEType(TypeFlags: TF));
4238 return Builder.CreateCall(Callee: F, Args: Ops);
4239 }
4240
4241 case SVE::BI__builtin_sve_svset_neonq_s8:
4242 case SVE::BI__builtin_sve_svset_neonq_s16:
4243 case SVE::BI__builtin_sve_svset_neonq_s32:
4244 case SVE::BI__builtin_sve_svset_neonq_s64:
4245 case SVE::BI__builtin_sve_svset_neonq_u8:
4246 case SVE::BI__builtin_sve_svset_neonq_u16:
4247 case SVE::BI__builtin_sve_svset_neonq_u32:
4248 case SVE::BI__builtin_sve_svset_neonq_u64:
4249 case SVE::BI__builtin_sve_svset_neonq_f16:
4250 case SVE::BI__builtin_sve_svset_neonq_f32:
4251 case SVE::BI__builtin_sve_svset_neonq_f64:
4252 case SVE::BI__builtin_sve_svset_neonq_bf16:
4253 case SVE::BI__builtin_sve_svset_neonq_mf8: {
4254 return Builder.CreateInsertVector(DstType: Ty, SrcVec: Ops[0], SubVec: Ops[1], Idx: uint64_t(0));
4255 }
4256
4257 case SVE::BI__builtin_sve_svget_neonq_s8:
4258 case SVE::BI__builtin_sve_svget_neonq_s16:
4259 case SVE::BI__builtin_sve_svget_neonq_s32:
4260 case SVE::BI__builtin_sve_svget_neonq_s64:
4261 case SVE::BI__builtin_sve_svget_neonq_u8:
4262 case SVE::BI__builtin_sve_svget_neonq_u16:
4263 case SVE::BI__builtin_sve_svget_neonq_u32:
4264 case SVE::BI__builtin_sve_svget_neonq_u64:
4265 case SVE::BI__builtin_sve_svget_neonq_f16:
4266 case SVE::BI__builtin_sve_svget_neonq_f32:
4267 case SVE::BI__builtin_sve_svget_neonq_f64:
4268 case SVE::BI__builtin_sve_svget_neonq_bf16:
4269 case SVE::BI__builtin_sve_svget_neonq_mf8: {
4270 return Builder.CreateExtractVector(DstType: Ty, SrcVec: Ops[0], Idx: uint64_t(0));
4271 }
4272
4273 case SVE::BI__builtin_sve_svdup_neonq_s8:
4274 case SVE::BI__builtin_sve_svdup_neonq_s16:
4275 case SVE::BI__builtin_sve_svdup_neonq_s32:
4276 case SVE::BI__builtin_sve_svdup_neonq_s64:
4277 case SVE::BI__builtin_sve_svdup_neonq_u8:
4278 case SVE::BI__builtin_sve_svdup_neonq_u16:
4279 case SVE::BI__builtin_sve_svdup_neonq_u32:
4280 case SVE::BI__builtin_sve_svdup_neonq_u64:
4281 case SVE::BI__builtin_sve_svdup_neonq_f16:
4282 case SVE::BI__builtin_sve_svdup_neonq_f32:
4283 case SVE::BI__builtin_sve_svdup_neonq_f64:
4284 case SVE::BI__builtin_sve_svdup_neonq_bf16:
4285 case SVE::BI__builtin_sve_svdup_neonq_mf8: {
4286 Value *Insert = Builder.CreateInsertVector(DstType: Ty, SrcVec: PoisonValue::get(T: Ty), SubVec: Ops[0],
4287 Idx: uint64_t(0));
4288 return Builder.CreateIntrinsic(ID: Intrinsic::aarch64_sve_dupq_lane, OverloadTypes: {Ty},
4289 Args: {Insert, Builder.getInt64(C: 0)});
4290 }
4291 }
4292
4293 /// Should not happen
4294 return nullptr;
4295}
4296
4297static void swapCommutativeSMEOperands(unsigned BuiltinID,
4298 SmallVectorImpl<Value *> &Ops) {
4299 unsigned MultiVec;
4300 switch (BuiltinID) {
4301 default:
4302 return;
4303 case SME::BI__builtin_sme_svsumla_za32_s8_vg4x1:
4304 MultiVec = 1;
4305 break;
4306 case SME::BI__builtin_sme_svsumla_za32_s8_vg4x2:
4307 case SME::BI__builtin_sme_svsudot_za32_s8_vg1x2:
4308 MultiVec = 2;
4309 break;
4310 case SME::BI__builtin_sme_svsudot_za32_s8_vg1x4:
4311 case SME::BI__builtin_sme_svsumla_za32_s8_vg4x4:
4312 MultiVec = 4;
4313 break;
4314 }
4315
4316 if (MultiVec > 0)
4317 for (unsigned I = 0; I < MultiVec; ++I)
4318 std::swap(a&: Ops[I + 1], b&: Ops[I + 1 + MultiVec]);
4319}
4320
4321Value *CodeGenFunction::EmitAArch64SMEBuiltinExpr(unsigned BuiltinID,
4322 const CallExpr *E) {
4323 auto *Builtin =
4324 findARMVectorIntrinsicInMap(IntrinsicMap: ArrayRef(AArch64SMEIntrinsicMap), BuiltinID,
4325 MapProvenSorted&: AArch64SMEIntrinsicsProvenSorted);
4326
4327 llvm::SmallVector<Value *, 4> Ops;
4328 SVETypeFlags TypeFlags(Builtin->TypeModifier);
4329 GetAArch64SVEProcessedOperands(BuiltinID, E, Ops, TypeFlags);
4330
4331 if (TypeFlags.isLoad() || TypeFlags.isStore())
4332 return EmitSMELd1St1(TypeFlags, Ops, IntID: Builtin->LLVMIntrinsic);
4333 if (TypeFlags.isReadZA() || TypeFlags.isWriteZA())
4334 return EmitSMEReadWrite(TypeFlags, Ops, IntID: Builtin->LLVMIntrinsic);
4335 if (BuiltinID == SME::BI__builtin_sme_svzero_mask_za ||
4336 BuiltinID == SME::BI__builtin_sme_svzero_za)
4337 return EmitSMEZero(TypeFlags, Ops, IntID: Builtin->LLVMIntrinsic);
4338 if (BuiltinID == SME::BI__builtin_sme_svldr_vnum_za ||
4339 BuiltinID == SME::BI__builtin_sme_svstr_vnum_za ||
4340 BuiltinID == SME::BI__builtin_sme_svldr_za ||
4341 BuiltinID == SME::BI__builtin_sme_svstr_za)
4342 return EmitSMELdrStr(TypeFlags, Ops, IntID: Builtin->LLVMIntrinsic);
4343
4344 // Emit set FPMR for intrinsics that require it
4345 if (TypeFlags.setsFPMR())
4346 Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_set_fpmr),
4347 Args: Ops.pop_back_val());
4348 // Handle builtins which require their multi-vector operands to be swapped
4349 swapCommutativeSMEOperands(BuiltinID, Ops);
4350
4351 auto isCntsBuiltin = [&]() {
4352 switch (BuiltinID) {
4353 default:
4354 return 0;
4355 case SME::BI__builtin_sme_svcntsb:
4356 return 8;
4357 case SME::BI__builtin_sme_svcntsh:
4358 return 4;
4359 case SME::BI__builtin_sme_svcntsw:
4360 return 2;
4361 }
4362 };
4363
4364 if (auto Mul = isCntsBuiltin()) {
4365 llvm::Value *Cntd =
4366 Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_sme_cntsd));
4367 return Builder.CreateMul(LHS: Cntd, RHS: llvm::ConstantInt::get(Ty: Int64Ty, V: Mul),
4368 Name: "mulsvl", /* HasNUW */ true, /* HasNSW */ true);
4369 }
4370
4371 // Should not happen!
4372 if (Builtin->LLVMIntrinsic == 0)
4373 return nullptr;
4374
4375 // Predicates must match the main datatype.
4376 for (Value *&Op : Ops)
4377 if (auto PredTy = dyn_cast<llvm::VectorType>(Val: Op->getType()))
4378 if (PredTy->getElementType()->isIntegerTy(BitWidth: 1))
4379 Op = EmitSVEPredicateCast(Pred: Op, VTy: getSVEType(TypeFlags));
4380
4381 if (BuiltinID == SME::BI__builtin_sme_svldr_zt ||
4382 BuiltinID == SME::BI__builtin_sme_svstr_zt) {
4383 Function *F = CGM.getIntrinsic(IID: Builtin->LLVMIntrinsic, Tys: Ops[1]->getType());
4384 return Builder.CreateCall(Callee: F, Args: Ops);
4385 }
4386
4387 Function *F =
4388 TypeFlags.isOverloadNone()
4389 ? CGM.getIntrinsic(IID: Builtin->LLVMIntrinsic)
4390 : CGM.getIntrinsic(IID: Builtin->LLVMIntrinsic, Tys: {getSVEType(TypeFlags)});
4391
4392 return Builder.CreateCall(Callee: F, Args: Ops);
4393}
4394
4395/// Helper for the read/write/add/inc X18 builtins: read the X18 register and
4396/// return it as an i8 pointer.
4397Value *readX18AsPtr(CodeGenFunction &CGF) {
4398 LLVMContext &Context = CGF.CGM.getLLVMContext();
4399 llvm::Metadata *Ops[] = {llvm::MDString::get(Context, Str: "x18")};
4400 llvm::MDNode *RegName = llvm::MDNode::get(Context, MDs: Ops);
4401 llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, MD: RegName);
4402 llvm::Function *F =
4403 CGF.CGM.getIntrinsic(IID: Intrinsic::read_register, Tys: {CGF.Int64Ty});
4404 llvm::Value *X18 = CGF.Builder.CreateCall(Callee: F, Args: Metadata);
4405 return CGF.Builder.CreateIntToPtr(V: X18, DestTy: CGF.Int8PtrTy);
4406}
4407
4408Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
4409 const CallExpr *E,
4410 llvm::Triple::ArchType Arch) {
4411 if (BuiltinID >= clang::AArch64::FirstSVEBuiltin &&
4412 BuiltinID <= clang::AArch64::LastSVEBuiltin)
4413 return EmitAArch64SVEBuiltinExpr(BuiltinID, E);
4414
4415 if (BuiltinID >= clang::AArch64::FirstSMEBuiltin &&
4416 BuiltinID <= clang::AArch64::LastSMEBuiltin)
4417 return EmitAArch64SMEBuiltinExpr(BuiltinID, E);
4418
4419 if (BuiltinID == Builtin::BI__builtin_cpu_supports)
4420 return EmitAArch64CpuSupports(E);
4421
4422 unsigned HintID = static_cast<unsigned>(-1);
4423 switch (BuiltinID) {
4424 default: break;
4425 case clang::AArch64::BI__builtin_arm_nop:
4426 HintID = 0;
4427 break;
4428 case clang::AArch64::BI__builtin_arm_yield:
4429 case clang::AArch64::BI__yield:
4430 HintID = 1;
4431 break;
4432 case clang::AArch64::BI__builtin_arm_wfe:
4433 case clang::AArch64::BI__wfe:
4434 HintID = 2;
4435 break;
4436 case clang::AArch64::BI__builtin_arm_wfi:
4437 case clang::AArch64::BI__wfi:
4438 HintID = 3;
4439 break;
4440 case clang::AArch64::BI__builtin_arm_sev:
4441 case clang::AArch64::BI__sev:
4442 HintID = 4;
4443 break;
4444 case clang::AArch64::BI__builtin_arm_sevl:
4445 case clang::AArch64::BI__sevl:
4446 HintID = 5;
4447 break;
4448 }
4449
4450 if (HintID != static_cast<unsigned>(-1)) {
4451 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_hint);
4452 return Builder.CreateCall(Callee: F, Args: llvm::ConstantInt::get(Ty: Int32Ty, V: HintID));
4453 }
4454
4455 if (BuiltinID == clang::AArch64::BI__builtin_arm_trap) {
4456 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_break);
4457 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
4458 return Builder.CreateCall(Callee: F, Args: Builder.CreateZExt(V: Arg, DestTy: CGM.Int32Ty));
4459 }
4460
4461 if (BuiltinID == clang::AArch64::BI__builtin_arm_get_sme_state) {
4462 // Create call to __arm_sme_state and store the results to the two pointers.
4463 CallInst *CI = EmitRuntimeCall(callee: CGM.CreateRuntimeFunction(
4464 Ty: llvm::FunctionType::get(Result: StructType::get(elt1: CGM.Int64Ty, elts: CGM.Int64Ty), Params: {},
4465 isVarArg: false),
4466 Name: "__arm_sme_state"));
4467 auto Attrs = AttributeList().addFnAttribute(C&: getLLVMContext(),
4468 Kind: "aarch64_pstate_sm_compatible");
4469 CI->setAttributes(Attrs);
4470 CI->setCallingConv(
4471 llvm::CallingConv::
4472 AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2);
4473 Builder.CreateStore(Val: Builder.CreateExtractValue(Agg: CI, Idxs: 0),
4474 Addr: EmitPointerWithAlignment(Addr: E->getArg(Arg: 0)));
4475 return Builder.CreateStore(Val: Builder.CreateExtractValue(Agg: CI, Idxs: 1),
4476 Addr: EmitPointerWithAlignment(Addr: E->getArg(Arg: 1)));
4477 }
4478
4479 if (BuiltinID == clang::AArch64::BI__builtin_arm_rbit) {
4480 assert((getContext().getTypeSize(E->getType()) == 32) &&
4481 "rbit of unusual size!");
4482 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
4483 return Builder.CreateCall(
4484 Callee: CGM.getIntrinsic(IID: Intrinsic::bitreverse, Tys: Arg->getType()), Args: Arg, Name: "rbit");
4485 }
4486 if (BuiltinID == clang::AArch64::BI__builtin_arm_rbit64) {
4487 assert((getContext().getTypeSize(E->getType()) == 64) &&
4488 "rbit of unusual size!");
4489 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
4490 return Builder.CreateCall(
4491 Callee: CGM.getIntrinsic(IID: Intrinsic::bitreverse, Tys: Arg->getType()), Args: Arg, Name: "rbit");
4492 }
4493
4494 if (BuiltinID == clang::AArch64::BI__builtin_arm_clz ||
4495 BuiltinID == clang::AArch64::BI__builtin_arm_clz64) {
4496 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
4497 Function *F = CGM.getIntrinsic(IID: Intrinsic::ctlz, Tys: Arg->getType());
4498 Value *Res = Builder.CreateCall(Callee: F, Args: {Arg, Builder.getInt1(V: false)});
4499 if (BuiltinID == clang::AArch64::BI__builtin_arm_clz64)
4500 Res = Builder.CreateTrunc(V: Res, DestTy: Builder.getInt32Ty());
4501 return Res;
4502 }
4503
4504 if (BuiltinID == clang::AArch64::BI__builtin_arm_cls) {
4505 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
4506 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_cls), Args: Arg,
4507 Name: "cls");
4508 }
4509 if (BuiltinID == clang::AArch64::BI__builtin_arm_cls64) {
4510 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
4511 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_cls64), Args: Arg,
4512 Name: "cls");
4513 }
4514
4515 if (BuiltinID == clang::AArch64::BI__builtin_arm_rint32zf ||
4516 BuiltinID == clang::AArch64::BI__builtin_arm_rint32z) {
4517 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
4518 llvm::Type *Ty = Arg->getType();
4519 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_frint32z, Tys: Ty),
4520 Args: Arg, Name: "frint32z");
4521 }
4522
4523 if (BuiltinID == clang::AArch64::BI__builtin_arm_rint64zf ||
4524 BuiltinID == clang::AArch64::BI__builtin_arm_rint64z) {
4525 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
4526 llvm::Type *Ty = Arg->getType();
4527 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_frint64z, Tys: Ty),
4528 Args: Arg, Name: "frint64z");
4529 }
4530
4531 if (BuiltinID == clang::AArch64::BI__builtin_arm_rint32xf ||
4532 BuiltinID == clang::AArch64::BI__builtin_arm_rint32x) {
4533 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
4534 llvm::Type *Ty = Arg->getType();
4535 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_frint32x, Tys: Ty),
4536 Args: Arg, Name: "frint32x");
4537 }
4538
4539 if (BuiltinID == clang::AArch64::BI__builtin_arm_rint64xf ||
4540 BuiltinID == clang::AArch64::BI__builtin_arm_rint64x) {
4541 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
4542 llvm::Type *Ty = Arg->getType();
4543 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_frint64x, Tys: Ty),
4544 Args: Arg, Name: "frint64x");
4545 }
4546
4547 if (BuiltinID == clang::AArch64::BI__builtin_arm_jcvt) {
4548 assert((getContext().getTypeSize(E->getType()) == 32) &&
4549 "__jcvt of unusual size!");
4550 llvm::Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
4551 return Builder.CreateCall(
4552 Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_fjcvtzs), Args: Arg);
4553 }
4554
4555 if (BuiltinID == clang::AArch64::BI__builtin_arm_ld64b ||
4556 BuiltinID == clang::AArch64::BI__builtin_arm_st64b ||
4557 BuiltinID == clang::AArch64::BI__builtin_arm_st64bv ||
4558 BuiltinID == clang::AArch64::BI__builtin_arm_st64bv0) {
4559 llvm::Value *MemAddr = EmitScalarExpr(E: E->getArg(Arg: 0));
4560 llvm::Value *ValPtr = EmitScalarExpr(E: E->getArg(Arg: 1));
4561
4562 if (BuiltinID == clang::AArch64::BI__builtin_arm_ld64b) {
4563 // Load from the address via an LLVM intrinsic, receiving a
4564 // tuple of 8 i64 words, and store each one to ValPtr.
4565 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_ld64b);
4566 llvm::Value *Val = Builder.CreateCall(Callee: F, Args: MemAddr);
4567 llvm::Value *ToRet;
4568 for (size_t i = 0; i < 8; i++) {
4569 llvm::Value *ValOffsetPtr =
4570 Builder.CreateGEP(Ty: Int64Ty, Ptr: ValPtr, IdxList: Builder.getInt32(C: i));
4571 Address Addr =
4572 Address(ValOffsetPtr, Int64Ty, CharUnits::fromQuantity(Quantity: 8));
4573 ToRet = Builder.CreateStore(Val: Builder.CreateExtractValue(Agg: Val, Idxs: i), Addr);
4574 }
4575 return ToRet;
4576 }
4577
4578 // Load 8 i64 words from ValPtr, and store them to the address
4579 // via an LLVM intrinsic.
4580 SmallVector<llvm::Value *, 9> Args;
4581 Args.push_back(Elt: MemAddr);
4582 for (size_t i = 0; i < 8; i++) {
4583 llvm::Value *ValOffsetPtr =
4584 Builder.CreateGEP(Ty: Int64Ty, Ptr: ValPtr, IdxList: Builder.getInt32(C: i));
4585 Address Addr = Address(ValOffsetPtr, Int64Ty, CharUnits::fromQuantity(Quantity: 8));
4586 Args.push_back(Elt: Builder.CreateLoad(Addr));
4587 }
4588
4589 auto Intr = (BuiltinID == clang::AArch64::BI__builtin_arm_st64b
4590 ? Intrinsic::aarch64_st64b
4591 : BuiltinID == clang::AArch64::BI__builtin_arm_st64bv
4592 ? Intrinsic::aarch64_st64bv
4593 : Intrinsic::aarch64_st64bv0);
4594 Function *F = CGM.getIntrinsic(IID: Intr);
4595 return Builder.CreateCall(Callee: F, Args);
4596 }
4597
4598 if (BuiltinID == clang::AArch64::BI__builtin_arm_rndr ||
4599 BuiltinID == clang::AArch64::BI__builtin_arm_rndrrs) {
4600
4601 auto Intr = (BuiltinID == clang::AArch64::BI__builtin_arm_rndr
4602 ? Intrinsic::aarch64_rndr
4603 : Intrinsic::aarch64_rndrrs);
4604 Function *F = CGM.getIntrinsic(IID: Intr);
4605 llvm::Value *Val = Builder.CreateCall(Callee: F);
4606 Value *RandomValue = Builder.CreateExtractValue(Agg: Val, Idxs: 0);
4607 Value *Status = Builder.CreateExtractValue(Agg: Val, Idxs: 1);
4608
4609 Address MemAddress = EmitPointerWithAlignment(Addr: E->getArg(Arg: 0));
4610 Builder.CreateStore(Val: RandomValue, Addr: MemAddress);
4611 Status = Builder.CreateZExt(V: Status, DestTy: Int32Ty);
4612 return Status;
4613 }
4614
4615 if (BuiltinID == clang::AArch64::BI__clear_cache) {
4616 Value *Begin = EmitScalarExpr(E: E->getArg(Arg: 0));
4617 Value *End = EmitScalarExpr(E: E->getArg(Arg: 1));
4618 Function *F = CGM.getIntrinsic(IID: Intrinsic::clear_cache, Tys: {CGM.DefaultPtrTy});
4619 return Builder.CreateCall(Callee: F, Args: {Begin, End});
4620 }
4621
4622 if ((BuiltinID == clang::AArch64::BI__builtin_arm_ldrex ||
4623 BuiltinID == clang::AArch64::BI__builtin_arm_ldaex) &&
4624 getContext().getTypeSize(T: E->getType()) == 128) {
4625 Function *F =
4626 CGM.getIntrinsic(IID: BuiltinID == clang::AArch64::BI__builtin_arm_ldaex
4627 ? Intrinsic::aarch64_ldaxp
4628 : Intrinsic::aarch64_ldxp);
4629
4630 Value *LdPtr = EmitScalarExpr(E: E->getArg(Arg: 0));
4631 Value *Val = Builder.CreateCall(Callee: F, Args: LdPtr, Name: "ldxp");
4632
4633 Value *Val0 = Builder.CreateExtractValue(Agg: Val, Idxs: 1);
4634 Value *Val1 = Builder.CreateExtractValue(Agg: Val, Idxs: 0);
4635 llvm::Type *Int128Ty = llvm::IntegerType::get(C&: getLLVMContext(), NumBits: 128);
4636 Val0 = Builder.CreateZExt(V: Val0, DestTy: Int128Ty);
4637 Val1 = Builder.CreateZExt(V: Val1, DestTy: Int128Ty);
4638
4639 Value *ShiftCst = llvm::ConstantInt::get(Ty: Int128Ty, V: 64);
4640 Val = Builder.CreateShl(LHS: Val0, RHS: ShiftCst, Name: "shl", HasNUW: true /* nuw */);
4641 Val = Builder.CreateOr(LHS: Val, RHS: Val1);
4642 return Builder.CreateBitCast(V: Val, DestTy: ConvertType(T: E->getType()));
4643 } else if (BuiltinID == clang::AArch64::BI__builtin_arm_ldrex ||
4644 BuiltinID == clang::AArch64::BI__builtin_arm_ldaex) {
4645 Value *LoadAddr = EmitScalarExpr(E: E->getArg(Arg: 0));
4646
4647 QualType Ty = E->getType();
4648 llvm::Type *RealResTy = ConvertType(T: Ty);
4649 llvm::Type *IntTy =
4650 llvm::IntegerType::get(C&: getLLVMContext(), NumBits: getContext().getTypeSize(T: Ty));
4651
4652 Function *F =
4653 CGM.getIntrinsic(IID: BuiltinID == clang::AArch64::BI__builtin_arm_ldaex
4654 ? Intrinsic::aarch64_ldaxr
4655 : Intrinsic::aarch64_ldxr,
4656 Tys: DefaultPtrTy);
4657 CallInst *Val = Builder.CreateCall(Callee: F, Args: LoadAddr, Name: "ldxr");
4658 Val->addParamAttr(
4659 ArgNo: 0, Attr: Attribute::get(Context&: getLLVMContext(), Kind: Attribute::ElementType, Ty: IntTy));
4660
4661 if (RealResTy->isPointerTy())
4662 return Builder.CreateIntToPtr(V: Val, DestTy: RealResTy);
4663
4664 llvm::Type *IntResTy = llvm::IntegerType::get(
4665 C&: getLLVMContext(), NumBits: CGM.getDataLayout().getTypeSizeInBits(Ty: RealResTy));
4666 return Builder.CreateBitCast(V: Builder.CreateTruncOrBitCast(V: Val, DestTy: IntResTy),
4667 DestTy: RealResTy);
4668 }
4669
4670 if ((BuiltinID == clang::AArch64::BI__builtin_arm_strex ||
4671 BuiltinID == clang::AArch64::BI__builtin_arm_stlex) &&
4672 getContext().getTypeSize(T: E->getArg(Arg: 0)->getType()) == 128) {
4673 Function *F =
4674 CGM.getIntrinsic(IID: BuiltinID == clang::AArch64::BI__builtin_arm_stlex
4675 ? Intrinsic::aarch64_stlxp
4676 : Intrinsic::aarch64_stxp);
4677 llvm::Type *STy = llvm::StructType::get(elt1: Int64Ty, elts: Int64Ty);
4678
4679 Address Tmp = CreateMemTempWithoutCast(T: E->getArg(Arg: 0)->getType());
4680 EmitAnyExprToMem(E: E->getArg(Arg: 0), Location: Tmp, Quals: Qualifiers(), /*init*/ IsInitializer: true);
4681
4682 Tmp = Tmp.withElementType(ElemTy: STy);
4683 llvm::Value *Val = Builder.CreateLoad(Addr: Tmp);
4684
4685 Value *Arg0 = Builder.CreateExtractValue(Agg: Val, Idxs: 0);
4686 Value *Arg1 = Builder.CreateExtractValue(Agg: Val, Idxs: 1);
4687 Value *StPtr = EmitScalarExpr(E: E->getArg(Arg: 1));
4688 return Builder.CreateCall(Callee: F, Args: {Arg0, Arg1, StPtr}, Name: "stxp");
4689 }
4690
4691 if (BuiltinID == clang::AArch64::BI__builtin_arm_strex ||
4692 BuiltinID == clang::AArch64::BI__builtin_arm_stlex) {
4693 Value *StoreVal = EmitScalarExpr(E: E->getArg(Arg: 0));
4694 Value *StoreAddr = EmitScalarExpr(E: E->getArg(Arg: 1));
4695
4696 QualType Ty = E->getArg(Arg: 0)->getType();
4697 llvm::Type *StoreTy =
4698 llvm::IntegerType::get(C&: getLLVMContext(), NumBits: getContext().getTypeSize(T: Ty));
4699
4700 if (StoreVal->getType()->isPointerTy())
4701 StoreVal = Builder.CreatePtrToInt(V: StoreVal, DestTy: Int64Ty);
4702 else {
4703 llvm::Type *IntTy = llvm::IntegerType::get(
4704 C&: getLLVMContext(),
4705 NumBits: CGM.getDataLayout().getTypeSizeInBits(Ty: StoreVal->getType()));
4706 StoreVal = Builder.CreateBitCast(V: StoreVal, DestTy: IntTy);
4707 StoreVal = Builder.CreateZExtOrBitCast(V: StoreVal, DestTy: Int64Ty);
4708 }
4709
4710 Function *F =
4711 CGM.getIntrinsic(IID: BuiltinID == clang::AArch64::BI__builtin_arm_stlex
4712 ? Intrinsic::aarch64_stlxr
4713 : Intrinsic::aarch64_stxr,
4714 Tys: StoreAddr->getType());
4715 CallInst *CI = Builder.CreateCall(Callee: F, Args: {StoreVal, StoreAddr}, Name: "stxr");
4716 CI->addParamAttr(
4717 ArgNo: 1, Attr: Attribute::get(Context&: getLLVMContext(), Kind: Attribute::ElementType, Ty: StoreTy));
4718 return CI;
4719 }
4720
4721 if (BuiltinID == clang::AArch64::BI__getReg ||
4722 BuiltinID == clang::AArch64::BI__setReg) {
4723 Expr::EvalResult Result;
4724 if (!E->getArg(Arg: 0)->EvaluateAsInt(Result, Ctx: CGM.getContext()))
4725 llvm_unreachable("Sema will ensure that the parameter is constant");
4726
4727 llvm::APSInt Value = Result.Val.getInt();
4728 LLVMContext &Context = CGM.getLLVMContext();
4729 std::string Reg = Value == 31 ? "sp" : "x" + toString(I: Value, Radix: 10);
4730
4731 llvm::Metadata *Ops[] = {llvm::MDString::get(Context, Str: Reg)};
4732 llvm::MDNode *RegName = llvm::MDNode::get(Context, MDs: Ops);
4733 llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, MD: RegName);
4734
4735 CallInst *CI;
4736 if (BuiltinID == clang::AArch64::BI__getReg) {
4737 llvm::Function *F =
4738 CGM.getIntrinsic(IID: Intrinsic::read_volatile_register, Tys: {Int64Ty});
4739 CI = Builder.CreateCall(Callee: F, Args: Metadata);
4740 } else {
4741 llvm::Function *F =
4742 CGM.getIntrinsic(IID: Intrinsic::write_volatile_register, Tys: {Int64Ty});
4743 CI = Builder.CreateCall(Callee: F, Args: {Metadata, EmitScalarExpr(E: E->getArg(Arg: 1))});
4744 }
4745 return CI;
4746 }
4747
4748 if (BuiltinID == clang::AArch64::BI__getRegFp ||
4749 BuiltinID == clang::AArch64::BI__setRegFp) {
4750 Expr::EvalResult Result;
4751 if (!E->getArg(Arg: 0)->EvaluateAsInt(Result, Ctx: CGM.getContext()))
4752 llvm_unreachable("Sema will ensure that the parameter is constant");
4753
4754 llvm::APSInt Value = Result.Val.getInt();
4755 LLVMContext &Context = CGM.getLLVMContext();
4756 std::string Reg = "d" + toString(I: Value, Radix: 10);
4757
4758 llvm::Metadata *Ops[] = {llvm::MDString::get(Context, Str: Reg)};
4759 llvm::MDNode *RegName = llvm::MDNode::get(Context, MDs: Ops);
4760 llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, MD: RegName);
4761
4762 llvm::Value *Ret;
4763 if (BuiltinID == clang::AArch64::BI__getRegFp) {
4764 llvm::Function *F =
4765 CGM.getIntrinsic(IID: Intrinsic::read_volatile_register, Tys: {Int64Ty});
4766 llvm::Value *Bits = Builder.CreateCall(Callee: F, Args: Metadata);
4767 Ret = Builder.CreateBitCast(V: Bits, DestTy: llvm::Type::getDoubleTy(C&: Context));
4768 } else {
4769 llvm::Value *Val = EmitScalarExpr(E: E->getArg(Arg: 1));
4770 llvm::Value *Bits = Builder.CreateBitCast(V: Val, DestTy: Int64Ty);
4771 llvm::Function *F =
4772 CGM.getIntrinsic(IID: Intrinsic::write_volatile_register, Tys: {Int64Ty});
4773 Ret = Builder.CreateCall(Callee: F, Args: {Metadata, Bits});
4774 }
4775 return Ret;
4776 }
4777
4778 if (BuiltinID == clang::AArch64::BI__break) {
4779 Expr::EvalResult Result;
4780 if (!E->getArg(Arg: 0)->EvaluateAsInt(Result, Ctx: CGM.getContext()))
4781 llvm_unreachable("Sema will ensure that the parameter is constant");
4782
4783 llvm::Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_break);
4784 return Builder.CreateCall(Callee: F, Args: {EmitScalarExpr(E: E->getArg(Arg: 0))});
4785 }
4786
4787 if (BuiltinID == clang::AArch64::BI__builtin_arm_clrex) {
4788 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_clrex);
4789 return Builder.CreateCall(Callee: F);
4790 }
4791
4792 if (BuiltinID == clang::AArch64::BI_ReadWriteBarrier)
4793 return Builder.CreateFence(Ordering: llvm::AtomicOrdering::SequentiallyConsistent,
4794 SSID: llvm::SyncScope::SingleThread);
4795
4796 // CRC32
4797 Intrinsic::ID CRCIntrinsicID = Intrinsic::not_intrinsic;
4798 switch (BuiltinID) {
4799 case clang::AArch64::BI__builtin_arm_crc32b:
4800 CRCIntrinsicID = Intrinsic::aarch64_crc32b; break;
4801 case clang::AArch64::BI__builtin_arm_crc32cb:
4802 CRCIntrinsicID = Intrinsic::aarch64_crc32cb; break;
4803 case clang::AArch64::BI__builtin_arm_crc32h:
4804 CRCIntrinsicID = Intrinsic::aarch64_crc32h; break;
4805 case clang::AArch64::BI__builtin_arm_crc32ch:
4806 CRCIntrinsicID = Intrinsic::aarch64_crc32ch; break;
4807 case clang::AArch64::BI__builtin_arm_crc32w:
4808 CRCIntrinsicID = Intrinsic::aarch64_crc32w; break;
4809 case clang::AArch64::BI__builtin_arm_crc32cw:
4810 CRCIntrinsicID = Intrinsic::aarch64_crc32cw; break;
4811 case clang::AArch64::BI__builtin_arm_crc32d:
4812 CRCIntrinsicID = Intrinsic::aarch64_crc32x; break;
4813 case clang::AArch64::BI__builtin_arm_crc32cd:
4814 CRCIntrinsicID = Intrinsic::aarch64_crc32cx; break;
4815 }
4816
4817 if (CRCIntrinsicID != Intrinsic::not_intrinsic) {
4818 Value *Arg0 = EmitScalarExpr(E: E->getArg(Arg: 0));
4819 Value *Arg1 = EmitScalarExpr(E: E->getArg(Arg: 1));
4820 Function *F = CGM.getIntrinsic(IID: CRCIntrinsicID);
4821
4822 llvm::Type *DataTy = F->getFunctionType()->getParamType(i: 1);
4823 Arg1 = Builder.CreateZExtOrBitCast(V: Arg1, DestTy: DataTy);
4824
4825 return Builder.CreateCall(Callee: F, Args: {Arg0, Arg1});
4826 }
4827
4828 // Memory Operations (MOPS)
4829 if (BuiltinID == AArch64::BI__builtin_arm_mops_memset_tag) {
4830 Value *Dst = EmitScalarExpr(E: E->getArg(Arg: 0));
4831 Value *Val = EmitScalarExpr(E: E->getArg(Arg: 1));
4832 Value *Size = EmitScalarExpr(E: E->getArg(Arg: 2));
4833 Val = Builder.CreateTrunc(V: Val, DestTy: Int8Ty);
4834 Size = Builder.CreateIntCast(V: Size, DestTy: Int64Ty, isSigned: false);
4835 return Builder.CreateCall(
4836 Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_mops_memset_tag), Args: {Dst, Val, Size});
4837 }
4838
4839 if (BuiltinID == AArch64::BI__builtin_arm_range_prefetch ||
4840 BuiltinID == AArch64::BI__builtin_arm_range_prefetch_x)
4841 return EmitRangePrefetchBuiltin(CGF&: *this, BuiltinID, E);
4842
4843 // Memory Tagging Extensions (MTE) Intrinsics
4844 Intrinsic::ID MTEIntrinsicID = Intrinsic::not_intrinsic;
4845 switch (BuiltinID) {
4846 case clang::AArch64::BI__builtin_arm_irg:
4847 MTEIntrinsicID = Intrinsic::aarch64_irg; break;
4848 case clang::AArch64::BI__builtin_arm_addg:
4849 MTEIntrinsicID = Intrinsic::aarch64_addg; break;
4850 case clang::AArch64::BI__builtin_arm_gmi:
4851 MTEIntrinsicID = Intrinsic::aarch64_gmi; break;
4852 case clang::AArch64::BI__builtin_arm_ldg:
4853 MTEIntrinsicID = Intrinsic::aarch64_ldg; break;
4854 case clang::AArch64::BI__builtin_arm_stg:
4855 MTEIntrinsicID = Intrinsic::aarch64_stg; break;
4856 case clang::AArch64::BI__builtin_arm_subp:
4857 MTEIntrinsicID = Intrinsic::aarch64_subp; break;
4858 }
4859
4860 if (MTEIntrinsicID != Intrinsic::not_intrinsic) {
4861 if (MTEIntrinsicID == Intrinsic::aarch64_irg) {
4862 Value *Pointer = EmitScalarExpr(E: E->getArg(Arg: 0));
4863 Value *Mask = EmitScalarExpr(E: E->getArg(Arg: 1));
4864 assert(Mask->getType()->getScalarSizeInBits() == 64 &&
4865 "SemaARM::BuiltinARMMemoryTaggingCall() enforces this");
4866 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: MTEIntrinsicID),
4867 Args: {Pointer, Mask});
4868 }
4869 if (MTEIntrinsicID == Intrinsic::aarch64_addg) {
4870 Value *Pointer = EmitScalarExpr(E: E->getArg(Arg: 0));
4871 Value *TagOffset = EmitScalarExpr(E: E->getArg(Arg: 1));
4872
4873 TagOffset = Builder.CreateZExt(V: TagOffset, DestTy: Int64Ty);
4874 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: MTEIntrinsicID),
4875 Args: {Pointer, TagOffset});
4876 }
4877 if (MTEIntrinsicID == Intrinsic::aarch64_gmi) {
4878 Value *Pointer = EmitScalarExpr(E: E->getArg(Arg: 0));
4879 Value *ExcludedMask = EmitScalarExpr(E: E->getArg(Arg: 1));
4880 assert(ExcludedMask->getType()->getScalarSizeInBits() == 64 &&
4881 "SemaARM::BuiltinARMMemoryTaggingCall() enforces this");
4882 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: MTEIntrinsicID),
4883 Args: {Pointer, ExcludedMask});
4884 }
4885 // Although it is possible to supply a different return
4886 // address (first arg) to this intrinsic, for now we set
4887 // return address same as input address.
4888 if (MTEIntrinsicID == Intrinsic::aarch64_ldg) {
4889 Value *TagAddress = EmitScalarExpr(E: E->getArg(Arg: 0));
4890 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: MTEIntrinsicID),
4891 Args: {TagAddress, TagAddress});
4892 }
4893 // Although it is possible to supply a different tag (to set)
4894 // to this intrinsic (as first arg), for now we supply
4895 // the tag that is in input address arg (common use case).
4896 if (MTEIntrinsicID == Intrinsic::aarch64_stg) {
4897 Value *TagAddress = EmitScalarExpr(E: E->getArg(Arg: 0));
4898 return Builder.CreateCall(Callee: CGM.getIntrinsic(IID: MTEIntrinsicID),
4899 Args: {TagAddress, TagAddress});
4900 }
4901 if (MTEIntrinsicID == Intrinsic::aarch64_subp) {
4902 Value *PointerA = EmitScalarExpr(E: E->getArg(Arg: 0));
4903 Value *PointerB = EmitScalarExpr(E: E->getArg(Arg: 1));
4904 return Builder.CreateCall(
4905 Callee: CGM.getIntrinsic(IID: MTEIntrinsicID), Args: {PointerA, PointerB});
4906 }
4907 }
4908
4909 if (BuiltinID == clang::AArch64::BI__builtin_arm_rsr ||
4910 BuiltinID == clang::AArch64::BI__builtin_arm_rsr64 ||
4911 BuiltinID == clang::AArch64::BI__builtin_arm_rsr128 ||
4912 BuiltinID == clang::AArch64::BI__builtin_arm_rsrp ||
4913 BuiltinID == clang::AArch64::BI__builtin_arm_wsr ||
4914 BuiltinID == clang::AArch64::BI__builtin_arm_wsr64 ||
4915 BuiltinID == clang::AArch64::BI__builtin_arm_wsr128 ||
4916 BuiltinID == clang::AArch64::BI__builtin_arm_wsrp) {
4917
4918 SpecialRegisterAccessKind AccessKind = Write;
4919 if (BuiltinID == clang::AArch64::BI__builtin_arm_rsr ||
4920 BuiltinID == clang::AArch64::BI__builtin_arm_rsr64 ||
4921 BuiltinID == clang::AArch64::BI__builtin_arm_rsr128 ||
4922 BuiltinID == clang::AArch64::BI__builtin_arm_rsrp)
4923 AccessKind = VolatileRead;
4924
4925 bool IsPointerBuiltin = BuiltinID == clang::AArch64::BI__builtin_arm_rsrp ||
4926 BuiltinID == clang::AArch64::BI__builtin_arm_wsrp;
4927
4928 bool Is32Bit = BuiltinID == clang::AArch64::BI__builtin_arm_rsr ||
4929 BuiltinID == clang::AArch64::BI__builtin_arm_wsr;
4930
4931 bool Is128Bit = BuiltinID == clang::AArch64::BI__builtin_arm_rsr128 ||
4932 BuiltinID == clang::AArch64::BI__builtin_arm_wsr128;
4933
4934 llvm::Type *ValueType;
4935 llvm::Type *RegisterType = Int64Ty;
4936 if (Is32Bit) {
4937 ValueType = Int32Ty;
4938 } else if (Is128Bit) {
4939 llvm::Type *Int128Ty =
4940 llvm::IntegerType::getInt128Ty(C&: CGM.getLLVMContext());
4941 ValueType = Int128Ty;
4942 RegisterType = Int128Ty;
4943 } else if (IsPointerBuiltin) {
4944 ValueType = VoidPtrTy;
4945 } else {
4946 ValueType = Int64Ty;
4947 };
4948
4949 return EmitSpecialRegisterBuiltin(CGF&: *this, E, RegisterType, ValueType,
4950 AccessKind);
4951 }
4952
4953 if (BuiltinID == clang::AArch64::BI_ReadStatusReg ||
4954 BuiltinID == clang::AArch64::BI_WriteStatusReg) {
4955 LLVMContext &Context = CGM.getLLVMContext();
4956
4957 unsigned SysReg =
4958 E->getArg(Arg: 0)->EvaluateKnownConstInt(Ctx: getContext()).getZExtValue();
4959
4960 std::string SysRegStr;
4961 llvm::raw_string_ostream(SysRegStr)
4962 << (0b10 | SysReg >> 14) << ":" << ((SysReg >> 11) & 7) << ":"
4963 << ((SysReg >> 7) & 15) << ":" << ((SysReg >> 3) & 15) << ":"
4964 << (SysReg & 7);
4965
4966 llvm::Metadata *Ops[] = { llvm::MDString::get(Context, Str: SysRegStr) };
4967 llvm::MDNode *RegName = llvm::MDNode::get(Context, MDs: Ops);
4968 llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, MD: RegName);
4969
4970 llvm::Type *RegisterType = Int64Ty;
4971 llvm::Type *Types[] = { RegisterType };
4972
4973 if (BuiltinID == clang::AArch64::BI_ReadStatusReg) {
4974 llvm::Function *F = CGM.getIntrinsic(IID: Intrinsic::read_register, Tys: Types);
4975
4976 return Builder.CreateCall(Callee: F, Args: Metadata);
4977 }
4978
4979 llvm::Function *F = CGM.getIntrinsic(IID: Intrinsic::write_register, Tys: Types);
4980 llvm::Value *ArgValue = EmitScalarExpr(E: E->getArg(Arg: 1));
4981 llvm::Value *Result = Builder.CreateCall(Callee: F, Args: {Metadata, ArgValue});
4982
4983 return Result;
4984 }
4985
4986 if (BuiltinID == clang::AArch64::BI__sys) {
4987 unsigned SysReg =
4988 E->getArg(Arg: 0)->EvaluateKnownConstInt(Ctx: getContext()).getZExtValue();
4989 const unsigned Op1 = SysReg >> 11;
4990 const unsigned CRn = (SysReg >> 7) & 0xf;
4991 const unsigned CRm = (SysReg >> 3) & 0xf;
4992 const unsigned Op2 = SysReg & 0x7;
4993
4994 Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Intrinsic::aarch64_sys),
4995 Args: {Builder.getInt32(C: Op1), Builder.getInt32(C: CRn),
4996 Builder.getInt32(C: CRm), Builder.getInt32(C: Op2),
4997 EmitScalarExpr(E: E->getArg(Arg: 1))});
4998
4999 // Return 0 for convenience, even though MSVC returns some other undefined
5000 // value.
5001 return ConstantInt::get(Ty: Builder.getInt32Ty(), V: 0);
5002 }
5003
5004 if (BuiltinID == clang::AArch64::BI_AddressOfReturnAddress) {
5005 llvm::Function *F =
5006 CGM.getIntrinsic(IID: Intrinsic::addressofreturnaddress, Tys: AllocaInt8PtrTy);
5007 return Builder.CreateCall(Callee: F);
5008 }
5009
5010 if (BuiltinID == clang::AArch64::BI__builtin_sponentry) {
5011 llvm::Function *F = CGM.getIntrinsic(IID: Intrinsic::sponentry, Tys: AllocaInt8PtrTy);
5012 return Builder.CreateCall(Callee: F);
5013 }
5014
5015 if (BuiltinID == clang::AArch64::BI__mulh ||
5016 BuiltinID == clang::AArch64::BI__umulh) {
5017 llvm::Type *ResType = ConvertType(T: E->getType());
5018 llvm::Type *Int128Ty = llvm::IntegerType::get(C&: getLLVMContext(), NumBits: 128);
5019
5020 bool IsSigned = BuiltinID == clang::AArch64::BI__mulh;
5021 Value *LHS =
5022 Builder.CreateIntCast(V: EmitScalarExpr(E: E->getArg(Arg: 0)), DestTy: Int128Ty, isSigned: IsSigned);
5023 Value *RHS =
5024 Builder.CreateIntCast(V: EmitScalarExpr(E: E->getArg(Arg: 1)), DestTy: Int128Ty, isSigned: IsSigned);
5025
5026 Value *MulResult, *HigherBits;
5027 if (IsSigned) {
5028 MulResult = Builder.CreateNSWMul(LHS, RHS);
5029 HigherBits = Builder.CreateAShr(LHS: MulResult, RHS: 64);
5030 } else {
5031 MulResult = Builder.CreateNUWMul(LHS, RHS);
5032 HigherBits = Builder.CreateLShr(LHS: MulResult, RHS: 64);
5033 }
5034 HigherBits = Builder.CreateIntCast(V: HigherBits, DestTy: ResType, isSigned: IsSigned);
5035
5036 return HigherBits;
5037 }
5038
5039 if (BuiltinID == AArch64::BI__writex18byte ||
5040 BuiltinID == AArch64::BI__writex18word ||
5041 BuiltinID == AArch64::BI__writex18dword ||
5042 BuiltinID == AArch64::BI__writex18qword) {
5043 // Process the args first
5044 Value *OffsetArg = EmitScalarExpr(E: E->getArg(Arg: 0));
5045 Value *DataArg = EmitScalarExpr(E: E->getArg(Arg: 1));
5046
5047 // Read x18 as i8*
5048 llvm::Value *X18 = readX18AsPtr(CGF&: *this);
5049
5050 // Store val at x18 + offset
5051 Value *Offset = Builder.CreateZExt(V: OffsetArg, DestTy: Int64Ty);
5052 Value *Ptr = Builder.CreateGEP(Ty: Int8Ty, Ptr: X18, IdxList: Offset);
5053 StoreInst *Store =
5054 Builder.CreateAlignedStore(Val: DataArg, Addr: Ptr, Align: CharUnits::One());
5055 return Store;
5056 }
5057
5058 if (BuiltinID == AArch64::BI__readx18byte ||
5059 BuiltinID == AArch64::BI__readx18word ||
5060 BuiltinID == AArch64::BI__readx18dword ||
5061 BuiltinID == AArch64::BI__readx18qword) {
5062 // Process the args first
5063 Value *OffsetArg = EmitScalarExpr(E: E->getArg(Arg: 0));
5064
5065 // Read x18 as i8*
5066 llvm::Value *X18 = readX18AsPtr(CGF&: *this);
5067
5068 // Load x18 + offset
5069 Value *Offset = Builder.CreateZExt(V: OffsetArg, DestTy: Int64Ty);
5070 Value *Ptr = Builder.CreateGEP(Ty: Int8Ty, Ptr: X18, IdxList: Offset);
5071 llvm::Type *IntTy = ConvertType(T: E->getType());
5072 LoadInst *Load = Builder.CreateAlignedLoad(Ty: IntTy, Addr: Ptr, Align: CharUnits::One());
5073 return Load;
5074 }
5075
5076 if (BuiltinID == AArch64::BI__addx18byte ||
5077 BuiltinID == AArch64::BI__addx18word ||
5078 BuiltinID == AArch64::BI__addx18dword ||
5079 BuiltinID == AArch64::BI__addx18qword ||
5080 BuiltinID == AArch64::BI__incx18byte ||
5081 BuiltinID == AArch64::BI__incx18word ||
5082 BuiltinID == AArch64::BI__incx18dword ||
5083 BuiltinID == AArch64::BI__incx18qword) {
5084 llvm::Type *IntTy;
5085 bool isIncrement;
5086 switch (BuiltinID) {
5087 case AArch64::BI__incx18byte:
5088 IntTy = Int8Ty;
5089 isIncrement = true;
5090 break;
5091 case AArch64::BI__incx18word:
5092 IntTy = Int16Ty;
5093 isIncrement = true;
5094 break;
5095 case AArch64::BI__incx18dword:
5096 IntTy = Int32Ty;
5097 isIncrement = true;
5098 break;
5099 case AArch64::BI__incx18qword:
5100 IntTy = Int64Ty;
5101 isIncrement = true;
5102 break;
5103 default:
5104 IntTy = ConvertType(T: E->getArg(Arg: 1)->getType());
5105 isIncrement = false;
5106 break;
5107 }
5108 // Process the args first
5109 Value *OffsetArg = EmitScalarExpr(E: E->getArg(Arg: 0));
5110 Value *ValToAdd =
5111 isIncrement ? ConstantInt::get(Ty: IntTy, V: 1) : EmitScalarExpr(E: E->getArg(Arg: 1));
5112
5113 // Read x18 as i8*
5114 llvm::Value *X18 = readX18AsPtr(CGF&: *this);
5115
5116 // Load x18 + offset
5117 Value *Offset = Builder.CreateZExt(V: OffsetArg, DestTy: Int64Ty);
5118 Value *Ptr = Builder.CreateGEP(Ty: Int8Ty, Ptr: X18, IdxList: Offset);
5119 LoadInst *Load = Builder.CreateAlignedLoad(Ty: IntTy, Addr: Ptr, Align: CharUnits::One());
5120
5121 // Add values
5122 Value *AddResult = Builder.CreateAdd(LHS: Load, RHS: ValToAdd);
5123
5124 // Store val at x18 + offset
5125 StoreInst *Store =
5126 Builder.CreateAlignedStore(Val: AddResult, Addr: Ptr, Align: CharUnits::One());
5127 return Store;
5128 }
5129
5130 if (BuiltinID == AArch64::BI_CopyDoubleFromInt64 ||
5131 BuiltinID == AArch64::BI_CopyFloatFromInt32 ||
5132 BuiltinID == AArch64::BI_CopyInt32FromFloat ||
5133 BuiltinID == AArch64::BI_CopyInt64FromDouble) {
5134 Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
5135 llvm::Type *RetTy = ConvertType(T: E->getType());
5136 return Builder.CreateBitCast(V: Arg, DestTy: RetTy);
5137 }
5138
5139 if (BuiltinID == AArch64::BI_CountLeadingOnes ||
5140 BuiltinID == AArch64::BI_CountLeadingOnes64 ||
5141 BuiltinID == AArch64::BI_CountLeadingZeros ||
5142 BuiltinID == AArch64::BI_CountLeadingZeros64) {
5143 Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
5144 llvm::Type *ArgType = Arg->getType();
5145
5146 if (BuiltinID == AArch64::BI_CountLeadingOnes ||
5147 BuiltinID == AArch64::BI_CountLeadingOnes64)
5148 Arg = Builder.CreateXor(LHS: Arg, RHS: Constant::getAllOnesValue(Ty: ArgType));
5149
5150 Function *F = CGM.getIntrinsic(IID: Intrinsic::ctlz, Tys: ArgType);
5151 Value *Result = Builder.CreateCall(Callee: F, Args: {Arg, Builder.getInt1(V: false)});
5152
5153 if (BuiltinID == AArch64::BI_CountLeadingOnes64 ||
5154 BuiltinID == AArch64::BI_CountLeadingZeros64)
5155 Result = Builder.CreateTrunc(V: Result, DestTy: Builder.getInt32Ty());
5156 return Result;
5157 }
5158
5159 if (BuiltinID == AArch64::BI_CountLeadingSigns ||
5160 BuiltinID == AArch64::BI_CountLeadingSigns64) {
5161 Value *Arg = EmitScalarExpr(E: E->getArg(Arg: 0));
5162
5163 Function *F = (BuiltinID == AArch64::BI_CountLeadingSigns)
5164 ? CGM.getIntrinsic(IID: Intrinsic::aarch64_cls)
5165 : CGM.getIntrinsic(IID: Intrinsic::aarch64_cls64);
5166
5167 Value *Result = Builder.CreateCall(Callee: F, Args: Arg, Name: "cls");
5168 if (BuiltinID == AArch64::BI_CountLeadingSigns64)
5169 Result = Builder.CreateTrunc(V: Result, DestTy: Builder.getInt32Ty());
5170 return Result;
5171 }
5172
5173 if (BuiltinID == AArch64::BI_CountOneBits ||
5174 BuiltinID == AArch64::BI_CountOneBits64) {
5175 Value *ArgValue = EmitScalarExpr(E: E->getArg(Arg: 0));
5176 llvm::Type *ArgType = ArgValue->getType();
5177 Function *F = CGM.getIntrinsic(IID: Intrinsic::ctpop, Tys: ArgType);
5178
5179 Value *Result = Builder.CreateCall(Callee: F, Args: ArgValue);
5180 if (BuiltinID == AArch64::BI_CountOneBits64)
5181 Result = Builder.CreateTrunc(V: Result, DestTy: Builder.getInt32Ty());
5182 return Result;
5183 }
5184
5185 if (BuiltinID == AArch64::BI_CountTrailingZeros ||
5186 BuiltinID == AArch64::BI_CountTrailingZeros64) {
5187 Value *ArgValue = EmitScalarExpr(E: E->getArg(Arg: 0));
5188 llvm::Type *ArgType = ArgValue->getType();
5189 Function *F = CGM.getIntrinsic(IID: Intrinsic::cttz, Tys: ArgType);
5190
5191 // MSVC leaves 0 undefined; use false for predictable codegen
5192 Value *Result = Builder.CreateCall(Callee: F, Args: {ArgValue, Builder.getInt1(V: false)});
5193 if (BuiltinID == AArch64::BI_CountTrailingZeros64)
5194 Result = Builder.CreateTrunc(V: Result, DestTy: Builder.getInt32Ty());
5195 return Result;
5196 }
5197
5198 if (BuiltinID == AArch64::BI__prefetch) {
5199 Value *Address = EmitScalarExpr(E: E->getArg(Arg: 0));
5200 Value *RW = llvm::ConstantInt::get(Ty: Int32Ty, V: 0);
5201 Value *Locality = ConstantInt::get(Ty: Int32Ty, V: 3);
5202 Value *Data = llvm::ConstantInt::get(Ty: Int32Ty, V: 1);
5203 Function *F = CGM.getIntrinsic(IID: Intrinsic::prefetch, Tys: Address->getType());
5204 return Builder.CreateCall(Callee: F, Args: {Address, RW, Locality, Data});
5205 }
5206
5207 if (BuiltinID == AArch64::BI__prefetch2) {
5208 Value *Address = EmitScalarExpr(E: E->getArg(Arg: 0));
5209 llvm::APSInt PrfOp = E->getArg(Arg: 1)->EvaluateKnownConstInt(Ctx: CGM.getContext());
5210 // Decode 5-bit PRFM encoding: bits[4:3]=type, bits[2:1]=target,
5211 // bit[0]=policy
5212 // type: PLD=0(load), PLI=1(instr), PST=2(store)
5213 // target: L1=0, L2=1, L3=2
5214 // policy: KEEP=0, STRM=1
5215 uint64_t Op = PrfOp.getZExtValue();
5216 uint64_t Type = (Op >> 3) & 0x3;
5217 uint64_t Target = (Op >> 1) & 0x3;
5218 uint64_t Policy = Op & 0x1;
5219 Value *RW = Builder.getInt32(C: Type == 2 ? 1 : 0);
5220 Value *Local = Builder.getInt32(C: Target);
5221 Value *IsStream = Builder.getInt32(C: Policy);
5222 Value *IsData = Builder.getInt32(C: Type == 1 ? 0 : 1);
5223 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_prefetch);
5224 return Builder.CreateCall(Callee: F, Args: {Address, RW, Local, IsStream, IsData});
5225 }
5226
5227 if (BuiltinID == AArch64::BI__hlt) {
5228 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_hlt);
5229 Builder.CreateCall(Callee: F, Args: {EmitScalarExpr(E: E->getArg(Arg: 0))});
5230
5231 // FIXME: MSVC documents __hlt as taking further arguments in X0-X3 and
5232 // returning the value in X0, like __hvc/__svc below. This ignores the
5233 // extra arguments and returns 0.
5234 return ConstantInt::get(Ty: Builder.getInt32Ty(), V: 0);
5235 }
5236
5237 if (BuiltinID == AArch64::BI__hvc || BuiltinID == AArch64::BI__svc) {
5238 unsigned IID = BuiltinID == AArch64::BI__svc ? Intrinsic::aarch64_svc
5239 : Intrinsic::aarch64_hvc;
5240 // The first argument is the instruction immediate; it must be a constant
5241 // (ImmArg on the intrinsic, encoded in the instruction). The remaining
5242 // arguments (at most four, enforced by Sema) are passed in X0-X3, widened
5243 // to 64 bits. The intrinsic takes exactly four register operands, so any
5244 // unused trailing ones are passed as poison and dropped during lowering.
5245 SmallVector<Value *, 5> Args{Builder.getInt32(
5246 C: GetIntegerConstantValue<uint32_t>(E: E->getArg(Arg: 0), Context&: getContext()))};
5247 for (unsigned I = 1, N = E->getNumArgs(); I < N; ++I) {
5248 Value *Arg = EmitScalarExpr(E: E->getArg(Arg: I));
5249 llvm::Type *ArgTy = Arg->getType();
5250 if (ArgTy->isPointerTy())
5251 Arg = Builder.CreatePtrToInt(V: Arg, DestTy: Int64Ty);
5252 else if (ArgTy->isFloatingPointTy())
5253 // Reinterpret the bits into the integer register, matching MSVC (e.g.
5254 // "fmov x0, d0" for a double).
5255 Arg = Builder.CreateZExtOrTrunc(
5256 V: Builder.CreateBitCast(
5257 V: Arg, DestTy: Builder.getIntNTy(N: ArgTy->getPrimitiveSizeInBits())),
5258 DestTy: Int64Ty);
5259 else
5260 Arg = Builder.CreateIntCast(
5261 V: Arg, DestTy: Int64Ty, isSigned: E->getArg(Arg: I)->getType()->isSignedIntegerType());
5262 Args.push_back(Elt: Arg);
5263 }
5264 while (Args.size() < 5)
5265 Args.push_back(Elt: llvm::PoisonValue::get(T: Int64Ty));
5266 Value *Call = Builder.CreateCall(Callee: CGM.getIntrinsic(IID), Args);
5267 // MSVC returns unsigned int, i.e. the low 32 bits of the X0 result.
5268 return Builder.CreateTrunc(V: Call, DestTy: Int32Ty);
5269 }
5270
5271 if (BuiltinID == NEON::BI__builtin_neon_vcvth_bf16_f32)
5272 return Builder.CreateFPTrunc(
5273 V: Builder.CreateBitCast(V: EmitScalarExpr(E: E->getArg(Arg: 0)),
5274 DestTy: Builder.getFloatTy()),
5275 DestTy: Builder.getBFloatTy());
5276
5277 // Handle MSVC intrinsics before argument evaluation to prevent double
5278 // evaluation.
5279 if (std::optional<MSVCIntrin> MsvcIntId =
5280 translateAarch64ToMsvcIntrin(BuiltinID))
5281 return EmitMSVCBuiltinExpr(BuiltinID: *MsvcIntId, E);
5282
5283 // Some intrinsics are equivalent - if they are use the base intrinsic ID.
5284 auto It = llvm::find_if(Range: NEONEquivalentIntrinsicMap, P: [BuiltinID](auto &P) {
5285 return P.first == BuiltinID;
5286 });
5287 if (It != end(arr: NEONEquivalentIntrinsicMap))
5288 BuiltinID = It->second;
5289
5290 // Check whether this is an SISD builtin.
5291 auto SISDMap = ArrayRef(AArch64SISDIntrinsicMap);
5292 const ARMNeonVectorIntrinsicInfo *Builtin = findARMVectorIntrinsicInMap(
5293 IntrinsicMap: SISDMap, BuiltinID, MapProvenSorted&: AArch64SISDIntrinsicsProvenSorted);
5294 bool IsSISD = (Builtin != nullptr);
5295
5296 // Find out if any arguments are required to be integer constant
5297 // expressions.
5298 unsigned ICEArguments = 0;
5299 ASTContext::GetBuiltinTypeError Error;
5300 getContext().GetBuiltinType(ID: BuiltinID, Error, IntegerConstantArgs: &ICEArguments);
5301 assert(Error == ASTContext::GE_None && "Should not codegen an error");
5302
5303 llvm::SmallVector<Value*, 4> Ops;
5304 Address PtrOp0 = Address::invalid();
5305 // Note the assumption that SISD intrinsics do not contain extra arguments.
5306 // TODO: Fold this into a single function call instead of, effectively, two
5307 // separate checks.
5308 bool HasExtraArg = !IsSISD && HasExtraNeonArgument(BuiltinID);
5309 unsigned NumArgs = E->getNumArgs() - (HasExtraArg ? 1 : 0);
5310 for (unsigned i = 0, e = NumArgs; i != e; i++) {
5311 if (i == 0) {
5312 switch (BuiltinID) {
5313 case NEON::BI__builtin_neon_vld1_v:
5314 case NEON::BI__builtin_neon_vld1q_v:
5315 case NEON::BI__builtin_neon_vld1_dup_v:
5316 case NEON::BI__builtin_neon_vld1q_dup_v:
5317 case NEON::BI__builtin_neon_vld1_lane_v:
5318 case NEON::BI__builtin_neon_vld1q_lane_v:
5319 case NEON::BI__builtin_neon_vst1_v:
5320 case NEON::BI__builtin_neon_vst1q_v:
5321 case NEON::BI__builtin_neon_vst1_lane_v:
5322 case NEON::BI__builtin_neon_vst1q_lane_v:
5323 case NEON::BI__builtin_neon_vldap1_lane_s64:
5324 case NEON::BI__builtin_neon_vldap1q_lane_s64:
5325 case NEON::BI__builtin_neon_vstl1_lane_s64:
5326 case NEON::BI__builtin_neon_vstl1q_lane_s64:
5327 // Get the alignment for the argument in addition to the value;
5328 // we'll use it later.
5329 PtrOp0 = EmitPointerWithAlignment(Addr: E->getArg(Arg: 0));
5330 Ops.push_back(Elt: PtrOp0.emitRawPointer(CGF&: *this));
5331 continue;
5332 }
5333 }
5334 Ops.push_back(Elt: EmitScalarOrConstFoldImmArg(ICEArguments, Idx: i, E));
5335 }
5336
5337 if (Builtin) {
5338 Value *Result = EmitCommonNeonSISDBuiltinExpr(CGF&: *this, SISDInfo: *Builtin, Ops, E);
5339 assert(Result && "SISD intrinsic should have been handled");
5340 return Result;
5341 }
5342
5343 const Expr *Arg = E->getArg(Arg: E->getNumArgs()-1);
5344 NeonTypeFlags Type(0);
5345 if (std::optional<llvm::APSInt> Result =
5346 Arg->getIntegerConstantExpr(Ctx: getContext()))
5347 // Determine the type of this overloaded NEON intrinsic.
5348 Type = NeonTypeFlags(Result->getZExtValue());
5349
5350 bool usgn = Type.isUnsigned();
5351 bool quad = Type.isQuad();
5352 unsigned Int;
5353
5354 // Not all intrinsics handled by the common case work for AArch64 yet, so only
5355 // defer to common code if it's been added to our special map.
5356 Builtin =
5357 findARMVectorIntrinsicInMap(IntrinsicMap: ArrayRef(AArch64SIMDIntrinsicMap), BuiltinID,
5358 MapProvenSorted&: AArch64SIMDIntrinsicsProvenSorted);
5359
5360 if (Builtin)
5361 return EmitCommonNeonBuiltinExpr(
5362 BuiltinID: Builtin->BuiltinID, LLVMIntrinsic: Builtin->LLVMIntrinsic, AltLLVMIntrinsic: Builtin->AltLLVMIntrinsic,
5363 NameHint: Builtin->NameHint, Modifier: Builtin->TypeModifier, E, Ops,
5364 /*never use addresses*/ PtrOp0: Address::invalid(), PtrOp1: Address::invalid(), Arch);
5365
5366 if (Value *V = EmitAArch64TblBuiltinExpr(CGF&: *this, BuiltinID, E, Ops, Arch))
5367 return V;
5368
5369 // Handle non-overloaded intrinsics first.
5370 switch (BuiltinID) {
5371 default: break;
5372 case NEON::BI__builtin_neon_vabsh_f16:
5373 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::fabs, Tys: HalfTy), Ops, name: "vabs");
5374 case NEON::BI__builtin_neon_vaddq_p128: {
5375 llvm::Type *Ty = GetNeonType(CGF: this, TypeFlags: NeonTypeFlags::Poly128);
5376 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
5377 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
5378 Ops[0] = Builder.CreateXor(LHS: Ops[0], RHS: Ops[1]);
5379 llvm::Type *Int128Ty = llvm::Type::getIntNTy(C&: getLLVMContext(), N: 128);
5380 return Builder.CreateBitCast(V: Ops[0], DestTy: Int128Ty);
5381 }
5382 case NEON::BI__builtin_neon_vldrq_p128: {
5383 llvm::Type *Int128Ty = llvm::Type::getIntNTy(C&: getLLVMContext(), N: 128);
5384 return Builder.CreateAlignedLoad(Ty: Int128Ty, Addr: Ops[0],
5385 Align: CharUnits::fromQuantity(Quantity: 16));
5386 }
5387 case NEON::BI__builtin_neon_vstrq_p128: {
5388 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
5389 }
5390 case NEON::BI__builtin_neon_vcvts_f32_u32:
5391 case NEON::BI__builtin_neon_vcvtd_f64_u64:
5392 usgn = true;
5393 [[fallthrough]];
5394 case NEON::BI__builtin_neon_vcvts_f32_s32:
5395 case NEON::BI__builtin_neon_vcvtd_f64_s64: {
5396 bool Is64 = Ops[0]->getType()->getPrimitiveSizeInBits() == 64;
5397 llvm::Type *InTy = Is64 ? Int64Ty : Int32Ty;
5398 llvm::Type *FTy = Is64 ? DoubleTy : FloatTy;
5399 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: InTy);
5400 if (usgn)
5401 return Builder.CreateUIToFP(V: Ops[0], DestTy: FTy);
5402 return Builder.CreateSIToFP(V: Ops[0], DestTy: FTy);
5403 }
5404 case NEON::BI__builtin_neon_vcvth_f16_u16:
5405 case NEON::BI__builtin_neon_vcvth_f16_u32:
5406 case NEON::BI__builtin_neon_vcvth_f16_u64:
5407 usgn = true;
5408 [[fallthrough]];
5409 case NEON::BI__builtin_neon_vcvth_f16_s16:
5410 case NEON::BI__builtin_neon_vcvth_f16_s32:
5411 case NEON::BI__builtin_neon_vcvth_f16_s64: {
5412 llvm::Type *FTy = HalfTy;
5413 llvm::Type *InTy;
5414 if (Ops[0]->getType()->getPrimitiveSizeInBits() == 64)
5415 InTy = Int64Ty;
5416 else if (Ops[0]->getType()->getPrimitiveSizeInBits() == 32)
5417 InTy = Int32Ty;
5418 else
5419 InTy = Int16Ty;
5420 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: InTy);
5421 if (usgn)
5422 return Builder.CreateUIToFP(V: Ops[0], DestTy: FTy);
5423 return Builder.CreateSIToFP(V: Ops[0], DestTy: FTy);
5424 }
5425 case NEON::BI__builtin_neon_vcvtah_u16_f16:
5426 case NEON::BI__builtin_neon_vcvtmh_u16_f16:
5427 case NEON::BI__builtin_neon_vcvtnh_u16_f16:
5428 case NEON::BI__builtin_neon_vcvtph_u16_f16:
5429 case NEON::BI__builtin_neon_vcvtah_s16_f16:
5430 case NEON::BI__builtin_neon_vcvtmh_s16_f16:
5431 case NEON::BI__builtin_neon_vcvtnh_s16_f16:
5432 case NEON::BI__builtin_neon_vcvtph_s16_f16: {
5433 llvm::Type *InTy = Int16Ty;
5434 llvm::Type* FTy = HalfTy;
5435 llvm::Type *Tys[2] = {InTy, FTy};
5436 switch (BuiltinID) {
5437 default: llvm_unreachable("missing builtin ID in switch!");
5438 case NEON::BI__builtin_neon_vcvtah_u16_f16:
5439 Int = Intrinsic::aarch64_neon_fcvtau; break;
5440 case NEON::BI__builtin_neon_vcvtmh_u16_f16:
5441 Int = Intrinsic::aarch64_neon_fcvtmu; break;
5442 case NEON::BI__builtin_neon_vcvtnh_u16_f16:
5443 Int = Intrinsic::aarch64_neon_fcvtnu; break;
5444 case NEON::BI__builtin_neon_vcvtph_u16_f16:
5445 Int = Intrinsic::aarch64_neon_fcvtpu; break;
5446 case NEON::BI__builtin_neon_vcvtah_s16_f16:
5447 Int = Intrinsic::aarch64_neon_fcvtas; break;
5448 case NEON::BI__builtin_neon_vcvtmh_s16_f16:
5449 Int = Intrinsic::aarch64_neon_fcvtms; break;
5450 case NEON::BI__builtin_neon_vcvtnh_s16_f16:
5451 Int = Intrinsic::aarch64_neon_fcvtns; break;
5452 case NEON::BI__builtin_neon_vcvtph_s16_f16:
5453 Int = Intrinsic::aarch64_neon_fcvtps; break;
5454 }
5455 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "fcvt");
5456 }
5457 case NEON::BI__builtin_neon_vcaleh_f16:
5458 case NEON::BI__builtin_neon_vcalth_f16:
5459 case NEON::BI__builtin_neon_vcageh_f16:
5460 case NEON::BI__builtin_neon_vcagth_f16: {
5461 llvm::Type* InTy = Int32Ty;
5462 llvm::Type* FTy = HalfTy;
5463 llvm::Type *Tys[2] = {InTy, FTy};
5464 switch (BuiltinID) {
5465 default: llvm_unreachable("missing builtin ID in switch!");
5466 case NEON::BI__builtin_neon_vcageh_f16:
5467 Int = Intrinsic::aarch64_neon_facge; break;
5468 case NEON::BI__builtin_neon_vcagth_f16:
5469 Int = Intrinsic::aarch64_neon_facgt; break;
5470 case NEON::BI__builtin_neon_vcaleh_f16:
5471 Int = Intrinsic::aarch64_neon_facge; std::swap(a&: Ops[0], b&: Ops[1]); break;
5472 case NEON::BI__builtin_neon_vcalth_f16:
5473 Int = Intrinsic::aarch64_neon_facgt; std::swap(a&: Ops[0], b&: Ops[1]); break;
5474 }
5475 Ops[0] = EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "facg");
5476 return Builder.CreateTrunc(V: Ops[0], DestTy: Int16Ty);
5477 }
5478 case NEON::BI__builtin_neon_vcvth_n_s16_f16:
5479 case NEON::BI__builtin_neon_vcvth_n_u16_f16: {
5480 llvm::Type* InTy = Int32Ty;
5481 llvm::Type* FTy = HalfTy;
5482 llvm::Type *Tys[2] = {InTy, FTy};
5483 switch (BuiltinID) {
5484 default: llvm_unreachable("missing builtin ID in switch!");
5485 case NEON::BI__builtin_neon_vcvth_n_s16_f16:
5486 Int = Intrinsic::aarch64_neon_vcvtfp2fxs; break;
5487 case NEON::BI__builtin_neon_vcvth_n_u16_f16:
5488 Int = Intrinsic::aarch64_neon_vcvtfp2fxu; break;
5489 }
5490 Ops[0] = EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "fcvth_n");
5491 return Builder.CreateTrunc(V: Ops[0], DestTy: Int16Ty);
5492 }
5493 case NEON::BI__builtin_neon_vcvth_n_f16_s16:
5494 case NEON::BI__builtin_neon_vcvth_n_f16_u16: {
5495 llvm::Type* FTy = HalfTy;
5496 llvm::Type* InTy = Int32Ty;
5497 llvm::Type *Tys[2] = {FTy, InTy};
5498 switch (BuiltinID) {
5499 default: llvm_unreachable("missing builtin ID in switch!");
5500 case NEON::BI__builtin_neon_vcvth_n_f16_s16:
5501 Int = Intrinsic::aarch64_neon_vcvtfxs2fp;
5502 Ops[0] = Builder.CreateSExt(V: Ops[0], DestTy: InTy, Name: "sext");
5503 break;
5504 case NEON::BI__builtin_neon_vcvth_n_f16_u16:
5505 Int = Intrinsic::aarch64_neon_vcvtfxu2fp;
5506 Ops[0] = Builder.CreateZExt(V: Ops[0], DestTy: InTy);
5507 break;
5508 }
5509 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "fcvth_n");
5510 }
5511 case NEON::BI__builtin_neon_vpaddd_s64: {
5512 // TODO: Isn't this handled by
5513 // EmitCommonNeonSISDBuiltinExpr?
5514 auto *Ty = llvm::FixedVectorType::get(ElementType: Int64Ty, NumElts: 2);
5515 // The vector is v2f64, so make sure it's bitcast to that.
5516 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty, Name: "v2i64");
5517 llvm::Value *Idx0 = llvm::ConstantInt::get(Ty: SizeTy, V: 0);
5518 llvm::Value *Idx1 = llvm::ConstantInt::get(Ty: SizeTy, V: 1);
5519 Value *Op0 = Builder.CreateExtractElement(Vec: Ops[0], Idx: Idx0, Name: "lane0");
5520 Value *Op1 = Builder.CreateExtractElement(Vec: Ops[0], Idx: Idx1, Name: "lane1");
5521 // Pairwise addition of a v2f64 into a scalar f64.
5522 return Builder.CreateAdd(LHS: Op0, RHS: Op1, Name: "vpaddd");
5523 }
5524 case NEON::BI__builtin_neon_vpaddd_f64: {
5525 auto *Ty = llvm::FixedVectorType::get(ElementType: DoubleTy, NumElts: 2);
5526 // The vector is v2f64, so make sure it's bitcast to that.
5527 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty, Name: "v2f64");
5528 llvm::Value *Idx0 = llvm::ConstantInt::get(Ty: SizeTy, V: 0);
5529 llvm::Value *Idx1 = llvm::ConstantInt::get(Ty: SizeTy, V: 1);
5530 Value *Op0 = Builder.CreateExtractElement(Vec: Ops[0], Idx: Idx0, Name: "lane0");
5531 Value *Op1 = Builder.CreateExtractElement(Vec: Ops[0], Idx: Idx1, Name: "lane1");
5532 // Pairwise addition of a v2f64 into a scalar f64.
5533 return Builder.CreateFAdd(L: Op0, R: Op1, Name: "vpaddd");
5534 }
5535 case NEON::BI__builtin_neon_vpadds_f32: {
5536 auto *Ty = llvm::FixedVectorType::get(ElementType: FloatTy, NumElts: 2);
5537 // The vector is v2f32, so make sure it's bitcast to that.
5538 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty, Name: "v2f32");
5539 llvm::Value *Idx0 = llvm::ConstantInt::get(Ty: SizeTy, V: 0);
5540 llvm::Value *Idx1 = llvm::ConstantInt::get(Ty: SizeTy, V: 1);
5541 Value *Op0 = Builder.CreateExtractElement(Vec: Ops[0], Idx: Idx0, Name: "lane0");
5542 Value *Op1 = Builder.CreateExtractElement(Vec: Ops[0], Idx: Idx1, Name: "lane1");
5543 // Pairwise addition of a v2f32 into a scalar f32.
5544 return Builder.CreateFAdd(L: Op0, R: Op1, Name: "vpaddd");
5545 }
5546 case NEON::BI__builtin_neon_vceqzd_s64:
5547 return EmitAArch64CompareBuiltinExpr(
5548 Op: Ops[0], Ty: ConvertType(T: E->getCallReturnType(Ctx: getContext())),
5549 Pred: ICmpInst::ICMP_EQ, Name: "vceqz");
5550 case NEON::BI__builtin_neon_vceqzd_f64:
5551 case NEON::BI__builtin_neon_vceqzs_f32:
5552 case NEON::BI__builtin_neon_vceqzh_f16:
5553 return EmitAArch64CompareBuiltinExpr(
5554 Op: Ops[0], Ty: ConvertType(T: E->getCallReturnType(Ctx: getContext())),
5555 Pred: ICmpInst::FCMP_OEQ, Name: "vceqz");
5556 case NEON::BI__builtin_neon_vcgezd_s64:
5557 return EmitAArch64CompareBuiltinExpr(
5558 Op: Ops[0], Ty: ConvertType(T: E->getCallReturnType(Ctx: getContext())),
5559 Pred: ICmpInst::ICMP_SGE, Name: "vcgez");
5560 case NEON::BI__builtin_neon_vcgezd_f64:
5561 case NEON::BI__builtin_neon_vcgezs_f32:
5562 case NEON::BI__builtin_neon_vcgezh_f16:
5563 return EmitAArch64CompareBuiltinExpr(
5564 Op: Ops[0], Ty: ConvertType(T: E->getCallReturnType(Ctx: getContext())),
5565 Pred: ICmpInst::FCMP_OGE, Name: "vcgez");
5566 case NEON::BI__builtin_neon_vclezd_s64:
5567 return EmitAArch64CompareBuiltinExpr(
5568 Op: Ops[0], Ty: ConvertType(T: E->getCallReturnType(Ctx: getContext())),
5569 Pred: ICmpInst::ICMP_SLE, Name: "vclez");
5570 case NEON::BI__builtin_neon_vclezd_f64:
5571 case NEON::BI__builtin_neon_vclezs_f32:
5572 case NEON::BI__builtin_neon_vclezh_f16:
5573 return EmitAArch64CompareBuiltinExpr(
5574 Op: Ops[0], Ty: ConvertType(T: E->getCallReturnType(Ctx: getContext())),
5575 Pred: ICmpInst::FCMP_OLE, Name: "vclez");
5576 case NEON::BI__builtin_neon_vcgtzd_s64:
5577 return EmitAArch64CompareBuiltinExpr(
5578 Op: Ops[0], Ty: ConvertType(T: E->getCallReturnType(Ctx: getContext())),
5579 Pred: ICmpInst::ICMP_SGT, Name: "vcgtz");
5580 case NEON::BI__builtin_neon_vcgtzd_f64:
5581 case NEON::BI__builtin_neon_vcgtzs_f32:
5582 case NEON::BI__builtin_neon_vcgtzh_f16:
5583 return EmitAArch64CompareBuiltinExpr(
5584 Op: Ops[0], Ty: ConvertType(T: E->getCallReturnType(Ctx: getContext())),
5585 Pred: ICmpInst::FCMP_OGT, Name: "vcgtz");
5586 case NEON::BI__builtin_neon_vcltzd_s64:
5587 return EmitAArch64CompareBuiltinExpr(
5588 Op: Ops[0], Ty: ConvertType(T: E->getCallReturnType(Ctx: getContext())),
5589 Pred: ICmpInst::ICMP_SLT, Name: "vcltz");
5590
5591 case NEON::BI__builtin_neon_vcltzd_f64:
5592 case NEON::BI__builtin_neon_vcltzs_f32:
5593 case NEON::BI__builtin_neon_vcltzh_f16:
5594 return EmitAArch64CompareBuiltinExpr(
5595 Op: Ops[0], Ty: ConvertType(T: E->getCallReturnType(Ctx: getContext())),
5596 Pred: ICmpInst::FCMP_OLT, Name: "vcltz");
5597
5598 case NEON::BI__builtin_neon_vceqzd_u64: {
5599 return EmitAArch64CompareBuiltinExpr(
5600 Op: Ops[0], Ty: ConvertType(T: E->getCallReturnType(Ctx: getContext())),
5601 Pred: ICmpInst::ICMP_EQ, Name: "vceqzd");
5602 }
5603 case NEON::BI__builtin_neon_vceqd_f64:
5604 case NEON::BI__builtin_neon_vcled_f64:
5605 case NEON::BI__builtin_neon_vcltd_f64:
5606 case NEON::BI__builtin_neon_vcged_f64:
5607 case NEON::BI__builtin_neon_vcgtd_f64: {
5608 llvm::CmpInst::Predicate P;
5609 switch (BuiltinID) {
5610 default: llvm_unreachable("missing builtin ID in switch!");
5611 case NEON::BI__builtin_neon_vceqd_f64: P = llvm::FCmpInst::FCMP_OEQ; break;
5612 case NEON::BI__builtin_neon_vcled_f64: P = llvm::FCmpInst::FCMP_OLE; break;
5613 case NEON::BI__builtin_neon_vcltd_f64: P = llvm::FCmpInst::FCMP_OLT; break;
5614 case NEON::BI__builtin_neon_vcged_f64: P = llvm::FCmpInst::FCMP_OGE; break;
5615 case NEON::BI__builtin_neon_vcgtd_f64: P = llvm::FCmpInst::FCMP_OGT; break;
5616 }
5617 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: DoubleTy);
5618 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: DoubleTy);
5619 if (P == llvm::FCmpInst::FCMP_OEQ)
5620 Ops[0] = Builder.CreateFCmp(P, LHS: Ops[0], RHS: Ops[1]);
5621 else
5622 Ops[0] = Builder.CreateFCmpS(P, LHS: Ops[0], RHS: Ops[1]);
5623 return Builder.CreateSExt(V: Ops[0], DestTy: Int64Ty, Name: "vcmpd");
5624 }
5625 case NEON::BI__builtin_neon_vceqs_f32:
5626 case NEON::BI__builtin_neon_vcles_f32:
5627 case NEON::BI__builtin_neon_vclts_f32:
5628 case NEON::BI__builtin_neon_vcges_f32:
5629 case NEON::BI__builtin_neon_vcgts_f32: {
5630 llvm::CmpInst::Predicate P;
5631 switch (BuiltinID) {
5632 default: llvm_unreachable("missing builtin ID in switch!");
5633 case NEON::BI__builtin_neon_vceqs_f32: P = llvm::FCmpInst::FCMP_OEQ; break;
5634 case NEON::BI__builtin_neon_vcles_f32: P = llvm::FCmpInst::FCMP_OLE; break;
5635 case NEON::BI__builtin_neon_vclts_f32: P = llvm::FCmpInst::FCMP_OLT; break;
5636 case NEON::BI__builtin_neon_vcges_f32: P = llvm::FCmpInst::FCMP_OGE; break;
5637 case NEON::BI__builtin_neon_vcgts_f32: P = llvm::FCmpInst::FCMP_OGT; break;
5638 }
5639 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: FloatTy);
5640 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: FloatTy);
5641 if (P == llvm::FCmpInst::FCMP_OEQ)
5642 Ops[0] = Builder.CreateFCmp(P, LHS: Ops[0], RHS: Ops[1]);
5643 else
5644 Ops[0] = Builder.CreateFCmpS(P, LHS: Ops[0], RHS: Ops[1]);
5645 return Builder.CreateSExt(V: Ops[0], DestTy: Int32Ty, Name: "vcmpd");
5646 }
5647 case NEON::BI__builtin_neon_vceqh_f16:
5648 case NEON::BI__builtin_neon_vcleh_f16:
5649 case NEON::BI__builtin_neon_vclth_f16:
5650 case NEON::BI__builtin_neon_vcgeh_f16:
5651 case NEON::BI__builtin_neon_vcgth_f16: {
5652 llvm::CmpInst::Predicate P;
5653 switch (BuiltinID) {
5654 default: llvm_unreachable("missing builtin ID in switch!");
5655 case NEON::BI__builtin_neon_vceqh_f16: P = llvm::FCmpInst::FCMP_OEQ; break;
5656 case NEON::BI__builtin_neon_vcleh_f16: P = llvm::FCmpInst::FCMP_OLE; break;
5657 case NEON::BI__builtin_neon_vclth_f16: P = llvm::FCmpInst::FCMP_OLT; break;
5658 case NEON::BI__builtin_neon_vcgeh_f16: P = llvm::FCmpInst::FCMP_OGE; break;
5659 case NEON::BI__builtin_neon_vcgth_f16: P = llvm::FCmpInst::FCMP_OGT; break;
5660 }
5661 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: HalfTy);
5662 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: HalfTy);
5663 if (P == llvm::FCmpInst::FCMP_OEQ)
5664 Ops[0] = Builder.CreateFCmp(P, LHS: Ops[0], RHS: Ops[1]);
5665 else
5666 Ops[0] = Builder.CreateFCmpS(P, LHS: Ops[0], RHS: Ops[1]);
5667 return Builder.CreateSExt(V: Ops[0], DestTy: Int16Ty, Name: "vcmpd");
5668 }
5669 case NEON::BI__builtin_neon_vceqd_s64:
5670 case NEON::BI__builtin_neon_vceqd_u64:
5671 case NEON::BI__builtin_neon_vcgtd_s64:
5672 case NEON::BI__builtin_neon_vcgtd_u64:
5673 case NEON::BI__builtin_neon_vcltd_s64:
5674 case NEON::BI__builtin_neon_vcltd_u64:
5675 case NEON::BI__builtin_neon_vcged_u64:
5676 case NEON::BI__builtin_neon_vcged_s64:
5677 case NEON::BI__builtin_neon_vcled_u64:
5678 case NEON::BI__builtin_neon_vcled_s64: {
5679 llvm::CmpInst::Predicate P;
5680 switch (BuiltinID) {
5681 default: llvm_unreachable("missing builtin ID in switch!");
5682 case NEON::BI__builtin_neon_vceqd_s64:
5683 case NEON::BI__builtin_neon_vceqd_u64:P = llvm::ICmpInst::ICMP_EQ;break;
5684 case NEON::BI__builtin_neon_vcgtd_s64:P = llvm::ICmpInst::ICMP_SGT;break;
5685 case NEON::BI__builtin_neon_vcgtd_u64:P = llvm::ICmpInst::ICMP_UGT;break;
5686 case NEON::BI__builtin_neon_vcltd_s64:P = llvm::ICmpInst::ICMP_SLT;break;
5687 case NEON::BI__builtin_neon_vcltd_u64:P = llvm::ICmpInst::ICMP_ULT;break;
5688 case NEON::BI__builtin_neon_vcged_u64:P = llvm::ICmpInst::ICMP_UGE;break;
5689 case NEON::BI__builtin_neon_vcged_s64:P = llvm::ICmpInst::ICMP_SGE;break;
5690 case NEON::BI__builtin_neon_vcled_u64:P = llvm::ICmpInst::ICMP_ULE;break;
5691 case NEON::BI__builtin_neon_vcled_s64:P = llvm::ICmpInst::ICMP_SLE;break;
5692 }
5693 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Int64Ty);
5694 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Int64Ty);
5695 Ops[0] = Builder.CreateICmp(P, LHS: Ops[0], RHS: Ops[1]);
5696 return Builder.CreateSExt(V: Ops[0], DestTy: Int64Ty, Name: "vceqd");
5697 }
5698 case NEON::BI__builtin_neon_vnegd_s64:
5699 return Builder.CreateNeg(V: Ops[0], Name: "vnegd");
5700 case NEON::BI__builtin_neon_vnegh_f16:
5701 return Builder.CreateFNeg(V: Ops[0], Name: "vnegh");
5702 case NEON::BI__builtin_neon_vtstd_s64:
5703 case NEON::BI__builtin_neon_vtstd_u64: {
5704 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Int64Ty);
5705 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Int64Ty);
5706 Ops[0] = Builder.CreateAnd(LHS: Ops[0], RHS: Ops[1]);
5707 Ops[0] = Builder.CreateICmp(P: ICmpInst::ICMP_NE, LHS: Ops[0],
5708 RHS: llvm::Constant::getNullValue(Ty: Int64Ty));
5709 return Builder.CreateSExt(V: Ops[0], DestTy: Int64Ty, Name: "vtstd");
5710 }
5711 case NEON::BI__builtin_neon_vset_lane_i8:
5712 case NEON::BI__builtin_neon_vset_lane_i16:
5713 case NEON::BI__builtin_neon_vset_lane_i32:
5714 case NEON::BI__builtin_neon_vset_lane_i64:
5715 case NEON::BI__builtin_neon_vset_lane_bf16:
5716 case NEON::BI__builtin_neon_vset_lane_f32:
5717 case NEON::BI__builtin_neon_vsetq_lane_i8:
5718 case NEON::BI__builtin_neon_vsetq_lane_i16:
5719 case NEON::BI__builtin_neon_vsetq_lane_i32:
5720 case NEON::BI__builtin_neon_vsetq_lane_i64:
5721 case NEON::BI__builtin_neon_vsetq_lane_bf16:
5722 case NEON::BI__builtin_neon_vsetq_lane_f32:
5723 return Builder.CreateInsertElement(Vec: Ops[1], NewElt: Ops[0], Idx: Ops[2], Name: "vset_lane");
5724 case NEON::BI__builtin_neon_vset_lane_f64:
5725 // The vector type needs a cast for the v1f64 variant.
5726 Ops[1] =
5727 Builder.CreateBitCast(V: Ops[1], DestTy: llvm::FixedVectorType::get(ElementType: DoubleTy, NumElts: 1));
5728 return Builder.CreateInsertElement(Vec: Ops[1], NewElt: Ops[0], Idx: Ops[2], Name: "vset_lane");
5729 case NEON::BI__builtin_neon_vset_lane_mf8:
5730 case NEON::BI__builtin_neon_vsetq_lane_mf8:
5731 // The input vector type needs a cast to scalar type.
5732 Ops[0] =
5733 Builder.CreateBitCast(V: Ops[0], DestTy: llvm::Type::getInt8Ty(C&: getLLVMContext()));
5734 return Builder.CreateInsertElement(Vec: Ops[1], NewElt: Ops[0], Idx: Ops[2], Name: "vset_lane");
5735 case NEON::BI__builtin_neon_vsetq_lane_f64:
5736 // The vector type needs a cast for the v2f64 variant.
5737 Ops[1] =
5738 Builder.CreateBitCast(V: Ops[1], DestTy: llvm::FixedVectorType::get(ElementType: DoubleTy, NumElts: 2));
5739 return Builder.CreateInsertElement(Vec: Ops[1], NewElt: Ops[0], Idx: Ops[2], Name: "vset_lane");
5740
5741 case NEON::BI__builtin_neon_vget_lane_i8:
5742 case NEON::BI__builtin_neon_vdupb_lane_i8:
5743 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vget_lane");
5744 case NEON::BI__builtin_neon_vgetq_lane_i8:
5745 case NEON::BI__builtin_neon_vdupb_laneq_i8:
5746 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vgetq_lane");
5747 case NEON::BI__builtin_neon_vget_lane_mf8:
5748 case NEON::BI__builtin_neon_vdupb_lane_mf8:
5749 case NEON::BI__builtin_neon_vgetq_lane_mf8:
5750 case NEON::BI__builtin_neon_vdupb_laneq_mf8:
5751 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vget_lane");
5752 case NEON::BI__builtin_neon_vget_lane_i16:
5753 case NEON::BI__builtin_neon_vduph_lane_i16:
5754 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vget_lane");
5755 case NEON::BI__builtin_neon_vgetq_lane_i16:
5756 case NEON::BI__builtin_neon_vduph_laneq_i16:
5757 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vgetq_lane");
5758 case NEON::BI__builtin_neon_vget_lane_i32:
5759 case NEON::BI__builtin_neon_vdups_lane_i32:
5760 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vget_lane");
5761 case NEON::BI__builtin_neon_vdups_lane_f32:
5762 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vdups_lane");
5763 case NEON::BI__builtin_neon_vgetq_lane_i32:
5764 case NEON::BI__builtin_neon_vdups_laneq_i32:
5765 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vgetq_lane");
5766 case NEON::BI__builtin_neon_vget_lane_i64:
5767 case NEON::BI__builtin_neon_vdupd_lane_i64:
5768 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vget_lane");
5769 case NEON::BI__builtin_neon_vdupd_lane_f64:
5770 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vdupd_lane");
5771 case NEON::BI__builtin_neon_vgetq_lane_i64:
5772 case NEON::BI__builtin_neon_vdupd_laneq_i64:
5773 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vgetq_lane");
5774 case NEON::BI__builtin_neon_vget_lane_f32:
5775 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vget_lane");
5776 case NEON::BI__builtin_neon_vget_lane_f64:
5777 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vget_lane");
5778 case NEON::BI__builtin_neon_vgetq_lane_f32:
5779 case NEON::BI__builtin_neon_vdups_laneq_f32:
5780 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vgetq_lane");
5781 case NEON::BI__builtin_neon_vgetq_lane_f64:
5782 case NEON::BI__builtin_neon_vdupd_laneq_f64:
5783 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vgetq_lane");
5784 case NEON::BI__builtin_neon_vaddh_f16:
5785 return Builder.CreateFAdd(L: Ops[0], R: Ops[1], Name: "vaddh");
5786 case NEON::BI__builtin_neon_vsubh_f16:
5787 return Builder.CreateFSub(L: Ops[0], R: Ops[1], Name: "vsubh");
5788 case NEON::BI__builtin_neon_vmulh_f16:
5789 return Builder.CreateFMul(L: Ops[0], R: Ops[1], Name: "vmulh");
5790 case NEON::BI__builtin_neon_vdivh_f16:
5791 return Builder.CreateFDiv(L: Ops[0], R: Ops[1], Name: "vdivh");
5792 case NEON::BI__builtin_neon_vfmah_f16:
5793 // NEON intrinsic puts accumulator first, unlike the LLVM fma.
5794 return emitCallMaybeConstrainedFPBuiltin(
5795 CGF&: *this, IntrinsicID: Intrinsic::fma, ConstrainedIntrinsicID: Intrinsic::experimental_constrained_fma, Ty: HalfTy,
5796 Args: {Ops[1], Ops[2], Ops[0]});
5797 case NEON::BI__builtin_neon_vfmsh_f16: {
5798 Value *Neg = Builder.CreateFNeg(V: Ops[1], Name: "vsubh");
5799
5800 // NEON intrinsic puts accumulator first, unlike the LLVM fma.
5801 return emitCallMaybeConstrainedFPBuiltin(
5802 CGF&: *this, IntrinsicID: Intrinsic::fma, ConstrainedIntrinsicID: Intrinsic::experimental_constrained_fma, Ty: HalfTy,
5803 Args: {Neg, Ops[2], Ops[0]});
5804 }
5805 case NEON::BI__builtin_neon_vaddd_s64:
5806 case NEON::BI__builtin_neon_vaddd_u64:
5807 return Builder.CreateAdd(LHS: Ops[0], RHS: Ops[1], Name: "vaddd");
5808 case NEON::BI__builtin_neon_vsubd_s64:
5809 case NEON::BI__builtin_neon_vsubd_u64:
5810 return Builder.CreateSub(LHS: Ops[0], RHS: Ops[1], Name: "vsubd");
5811 case NEON::BI__builtin_neon_vqdmlalh_s16:
5812 case NEON::BI__builtin_neon_vqdmlslh_s16: {
5813 SmallVector<Value *, 2> ProductOps;
5814 ProductOps.push_back(Elt: vectorWrapScalar16(Op: Ops[1]));
5815 ProductOps.push_back(Elt: vectorWrapScalar16(Op: Ops[2]));
5816 auto *VTy = llvm::FixedVectorType::get(ElementType: Int32Ty, NumElts: 4);
5817 Ops[1] = EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_sqdmull, Tys: VTy),
5818 Ops&: ProductOps, name: "vqdmlXl");
5819 Constant *CI = ConstantInt::get(Ty: SizeTy, V: 0);
5820 Ops[1] = Builder.CreateExtractElement(Vec: Ops[1], Idx: CI, Name: "lane0");
5821
5822 unsigned AccumInt = BuiltinID == NEON::BI__builtin_neon_vqdmlalh_s16
5823 ? Intrinsic::aarch64_neon_sqadd
5824 : Intrinsic::aarch64_neon_sqsub;
5825 // Drop the 2nd multiplication argument before the accumulation
5826 Ops.pop_back();
5827 return EmitNeonCall(F: CGM.getIntrinsic(IID: AccumInt, Tys: Int32Ty), Ops, name: "vqdmlXl");
5828 }
5829 case NEON::BI__builtin_neon_vqshlud_n_s64: {
5830 Ops[1] = Builder.CreateZExt(V: Ops[1], DestTy: Int64Ty);
5831 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_sqshlu, Tys: Int64Ty),
5832 Ops, name: "vqshlu_n");
5833 }
5834 case NEON::BI__builtin_neon_vqshld_n_u64:
5835 case NEON::BI__builtin_neon_vqshld_n_s64: {
5836 Int = BuiltinID == NEON::BI__builtin_neon_vqshld_n_u64
5837 ? Intrinsic::aarch64_neon_uqshl
5838 : Intrinsic::aarch64_neon_sqshl;
5839 Ops[1] = Builder.CreateZExt(V: Ops[1], DestTy: Int64Ty);
5840 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Int64Ty), Ops, name: "vqshl_n");
5841 }
5842 case NEON::BI__builtin_neon_vrshrd_n_u64:
5843 case NEON::BI__builtin_neon_vrshrd_n_s64: {
5844 Int = BuiltinID == NEON::BI__builtin_neon_vrshrd_n_u64
5845 ? Intrinsic::aarch64_neon_urshl
5846 : Intrinsic::aarch64_neon_srshl;
5847 int SV = cast<ConstantInt>(Val: Ops[1])->getSExtValue();
5848 Ops[1] = ConstantInt::get(Ty: Int64Ty, V: -SV);
5849 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Int64Ty), Ops, name: "vrshr_n");
5850 }
5851 case NEON::BI__builtin_neon_vrsrad_n_u64:
5852 case NEON::BI__builtin_neon_vrsrad_n_s64: {
5853 Int = BuiltinID == NEON::BI__builtin_neon_vrsrad_n_u64
5854 ? Intrinsic::aarch64_neon_urshl
5855 : Intrinsic::aarch64_neon_srshl;
5856 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Int64Ty);
5857 Ops[2] = Builder.CreateNeg(V: Ops[2]);
5858 Ops[1] = Builder.CreateCall(Callee: CGM.getIntrinsic(IID: Int, Tys: Int64Ty),
5859 Args: {Ops[1], Builder.CreateSExt(V: Ops[2], DestTy: Int64Ty)});
5860 return Builder.CreateAdd(LHS: Ops[0], RHS: Builder.CreateBitCast(V: Ops[1], DestTy: Int64Ty));
5861 }
5862 case NEON::BI__builtin_neon_vshld_n_s64:
5863 case NEON::BI__builtin_neon_vshld_n_u64: {
5864 llvm::ConstantInt *Amt = cast<ConstantInt>(Val: Ops[1]);
5865 return Builder.CreateShl(
5866 LHS: Ops[0], RHS: ConstantInt::get(Ty: Int64Ty, V: Amt->getZExtValue()), Name: "shld_n");
5867 }
5868 case NEON::BI__builtin_neon_vshrd_n_s64: {
5869 llvm::ConstantInt *Amt = cast<ConstantInt>(Val: Ops[1]);
5870 return Builder.CreateAShr(
5871 LHS: Ops[0], RHS: ConstantInt::get(Ty: Int64Ty, V: std::min(a: static_cast<uint64_t>(63),
5872 b: Amt->getZExtValue())),
5873 Name: "shrd_n");
5874 }
5875 case NEON::BI__builtin_neon_vshrd_n_u64: {
5876 llvm::ConstantInt *Amt = cast<ConstantInt>(Val: Ops[1]);
5877 uint64_t ShiftAmt = Amt->getZExtValue();
5878 // Right-shifting an unsigned value by its size yields 0.
5879 if (ShiftAmt == 64)
5880 return ConstantInt::get(Ty: Int64Ty, V: 0);
5881 return Builder.CreateLShr(LHS: Ops[0], RHS: ConstantInt::get(Ty: Int64Ty, V: ShiftAmt),
5882 Name: "shrd_n");
5883 }
5884 case NEON::BI__builtin_neon_vsrad_n_s64: {
5885 llvm::ConstantInt *Amt = cast<ConstantInt>(Val: Ops[2]);
5886 Ops[1] = Builder.CreateAShr(
5887 LHS: Ops[1], RHS: ConstantInt::get(Ty: Int64Ty, V: std::min(a: static_cast<uint64_t>(63),
5888 b: Amt->getZExtValue())),
5889 Name: "shrd_n");
5890 return Builder.CreateAdd(LHS: Ops[0], RHS: Ops[1]);
5891 }
5892 case NEON::BI__builtin_neon_vsrad_n_u64: {
5893 llvm::ConstantInt *Amt = cast<ConstantInt>(Val: Ops[2]);
5894 uint64_t ShiftAmt = Amt->getZExtValue();
5895 // Right-shifting an unsigned value by its size yields 0.
5896 // As Op + 0 = Op, return Ops[0] directly.
5897 if (ShiftAmt == 64)
5898 return Ops[0];
5899 Ops[1] = Builder.CreateLShr(LHS: Ops[1], RHS: ConstantInt::get(Ty: Int64Ty, V: ShiftAmt),
5900 Name: "shrd_n");
5901 return Builder.CreateAdd(LHS: Ops[0], RHS: Ops[1]);
5902 }
5903 case NEON::BI__builtin_neon_vqdmlalh_lane_s16:
5904 case NEON::BI__builtin_neon_vqdmlalh_laneq_s16:
5905 case NEON::BI__builtin_neon_vqdmlslh_lane_s16:
5906 case NEON::BI__builtin_neon_vqdmlslh_laneq_s16: {
5907 Ops[2] = Builder.CreateExtractElement(Vec: Ops[2], Idx: Ops[3], Name: "lane");
5908 SmallVector<Value *, 2> ProductOps;
5909 ProductOps.push_back(Elt: vectorWrapScalar16(Op: Ops[1]));
5910 ProductOps.push_back(Elt: vectorWrapScalar16(Op: Ops[2]));
5911 auto *VTy = llvm::FixedVectorType::get(ElementType: Int32Ty, NumElts: 4);
5912 Ops[1] = EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_sqdmull, Tys: VTy),
5913 Ops&: ProductOps, name: "vqdmlXl");
5914 Constant *CI = ConstantInt::get(Ty: SizeTy, V: 0);
5915 Ops[1] = Builder.CreateExtractElement(Vec: Ops[1], Idx: CI, Name: "lane0");
5916 // Drop lane-selection and the corresponding vector argument (these have
5917 // already been used)
5918 Ops.pop_back_n(NumItems: 2);
5919
5920 unsigned AccInt = (BuiltinID == NEON::BI__builtin_neon_vqdmlalh_lane_s16 ||
5921 BuiltinID == NEON::BI__builtin_neon_vqdmlalh_laneq_s16)
5922 ? Intrinsic::aarch64_neon_sqadd
5923 : Intrinsic::aarch64_neon_sqsub;
5924 return EmitNeonCall(F: CGM.getIntrinsic(IID: AccInt, Tys: Int32Ty), Ops, name: "vqdmlXl");
5925 }
5926 case NEON::BI__builtin_neon_vqdmlals_s32:
5927 case NEON::BI__builtin_neon_vqdmlsls_s32: {
5928 SmallVector<Value *, 2> ProductOps;
5929 ProductOps.push_back(Elt: Ops[1]);
5930 ProductOps.push_back(Elt: Ops[2]);
5931 Ops[1] =
5932 EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_sqdmulls_scalar),
5933 Ops&: ProductOps, name: "vqdmlXl");
5934
5935 unsigned AccumInt = BuiltinID == NEON::BI__builtin_neon_vqdmlals_s32
5936 ? Intrinsic::aarch64_neon_sqadd
5937 : Intrinsic::aarch64_neon_sqsub;
5938 // Drop the 2nd multiplication argument before the accumulation
5939 Ops.pop_back();
5940 return EmitNeonCall(F: CGM.getIntrinsic(IID: AccumInt, Tys: Int64Ty), Ops, name: "vqdmlXl");
5941 }
5942 case NEON::BI__builtin_neon_vqdmlals_lane_s32:
5943 case NEON::BI__builtin_neon_vqdmlals_laneq_s32:
5944 case NEON::BI__builtin_neon_vqdmlsls_lane_s32:
5945 case NEON::BI__builtin_neon_vqdmlsls_laneq_s32: {
5946 Ops[2] = Builder.CreateExtractElement(Vec: Ops[2], Idx: Ops[3], Name: "lane");
5947 SmallVector<Value *, 2> ProductOps;
5948 ProductOps.push_back(Elt: Ops[1]);
5949 ProductOps.push_back(Elt: Ops[2]);
5950 Ops[1] =
5951 EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_sqdmulls_scalar),
5952 Ops&: ProductOps, name: "vqdmlXl");
5953 // Drop lane-selection and the corresponding vector argument (these have
5954 // already been used)
5955 Ops.pop_back_n(NumItems: 2);
5956
5957 unsigned AccInt = (BuiltinID == NEON::BI__builtin_neon_vqdmlals_lane_s32 ||
5958 BuiltinID == NEON::BI__builtin_neon_vqdmlals_laneq_s32)
5959 ? Intrinsic::aarch64_neon_sqadd
5960 : Intrinsic::aarch64_neon_sqsub;
5961 return EmitNeonCall(F: CGM.getIntrinsic(IID: AccInt, Tys: Int64Ty), Ops, name: "vqdmlXl");
5962 }
5963 case NEON::BI__builtin_neon_vget_lane_bf16:
5964 case NEON::BI__builtin_neon_vduph_lane_bf16:
5965 case NEON::BI__builtin_neon_vduph_lane_f16: {
5966 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vget_lane");
5967 }
5968 case NEON::BI__builtin_neon_vgetq_lane_bf16:
5969 case NEON::BI__builtin_neon_vduph_laneq_bf16:
5970 case NEON::BI__builtin_neon_vduph_laneq_f16: {
5971 return Builder.CreateExtractElement(Vec: Ops[0], Idx: Ops[1], Name: "vgetq_lane");
5972 }
5973 case NEON::BI__builtin_neon_vcvt_bf16_f32: {
5974 llvm::Type *V4F32 = FixedVectorType::get(ElementType: Builder.getFloatTy(), NumElts: 4);
5975 llvm::Type *V4BF16 = FixedVectorType::get(ElementType: Builder.getBFloatTy(), NumElts: 4);
5976 return Builder.CreateFPTrunc(V: Builder.CreateBitCast(V: Ops[0], DestTy: V4F32), DestTy: V4BF16);
5977 }
5978 case NEON::BI__builtin_neon_vcvtq_low_bf16_f32: {
5979 SmallVector<int, 16> ConcatMask(8);
5980 std::iota(first: ConcatMask.begin(), last: ConcatMask.end(), value: 0);
5981 llvm::Type *V4F32 = FixedVectorType::get(ElementType: Builder.getFloatTy(), NumElts: 4);
5982 llvm::Type *V4BF16 = FixedVectorType::get(ElementType: Builder.getBFloatTy(), NumElts: 4);
5983 llvm::Value *Trunc =
5984 Builder.CreateFPTrunc(V: Builder.CreateBitCast(V: Ops[0], DestTy: V4F32), DestTy: V4BF16);
5985 return Builder.CreateShuffleVector(
5986 V1: Trunc, V2: ConstantAggregateZero::get(Ty: V4BF16), Mask: ConcatMask);
5987 }
5988 case NEON::BI__builtin_neon_vcvtq_high_bf16_f32: {
5989 SmallVector<int, 16> ConcatMask(8);
5990 std::iota(first: ConcatMask.begin(), last: ConcatMask.end(), value: 0);
5991 SmallVector<int, 16> LoMask(4);
5992 std::iota(first: LoMask.begin(), last: LoMask.end(), value: 0);
5993 llvm::Type *V4F32 = FixedVectorType::get(ElementType: Builder.getFloatTy(), NumElts: 4);
5994 llvm::Type *V4BF16 = FixedVectorType::get(ElementType: Builder.getBFloatTy(), NumElts: 4);
5995 llvm::Type *V8BF16 = FixedVectorType::get(ElementType: Builder.getBFloatTy(), NumElts: 8);
5996 llvm::Value *Inactive = Builder.CreateShuffleVector(
5997 V: Builder.CreateBitCast(V: Ops[0], DestTy: V8BF16), Mask: LoMask);
5998 llvm::Value *Trunc =
5999 Builder.CreateFPTrunc(V: Builder.CreateBitCast(V: Ops[1], DestTy: V4F32), DestTy: V4BF16);
6000 return Builder.CreateShuffleVector(V1: Inactive, V2: Trunc, Mask: ConcatMask);
6001 }
6002 case NEON::BI__builtin_neon_vcvt_f16_f32: {
6003 llvm::Type *V4F32 = FixedVectorType::get(ElementType: Builder.getFloatTy(), NumElts: 4);
6004 llvm::Type *V4F16 = FixedVectorType::get(ElementType: Builder.getHalfTy(), NumElts: 4);
6005 return Builder.CreateFPTrunc(V: Builder.CreateBitCast(V: Ops[0], DestTy: V4F32), DestTy: V4F16);
6006 }
6007 case NEON::BI__builtin_neon_vcvt_f32_f16: {
6008 llvm::Type *V4F32 = FixedVectorType::get(ElementType: Builder.getFloatTy(), NumElts: 4);
6009 llvm::Type *V4F16 = FixedVectorType::get(ElementType: Builder.getHalfTy(), NumElts: 4);
6010 return Builder.CreateFPExt(V: Builder.CreateBitCast(V: Ops[0], DestTy: V4F16), DestTy: V4F32);
6011 }
6012
6013 case clang::AArch64::BI_InterlockedAdd:
6014 case clang::AArch64::BI_InterlockedAdd_acq:
6015 case clang::AArch64::BI_InterlockedAdd_rel:
6016 case clang::AArch64::BI_InterlockedAdd_nf:
6017 case clang::AArch64::BI_InterlockedAdd64:
6018 case clang::AArch64::BI_InterlockedAdd64_acq:
6019 case clang::AArch64::BI_InterlockedAdd64_rel:
6020 case clang::AArch64::BI_InterlockedAdd64_nf: {
6021 Address DestAddr = CheckAtomicAlignment(CGF&: *this, E);
6022 Value *Val = Ops[1];
6023 llvm::AtomicOrdering Ordering;
6024 switch (BuiltinID) {
6025 case clang::AArch64::BI_InterlockedAdd:
6026 case clang::AArch64::BI_InterlockedAdd64:
6027 Ordering = llvm::AtomicOrdering::SequentiallyConsistent;
6028 break;
6029 case clang::AArch64::BI_InterlockedAdd_acq:
6030 case clang::AArch64::BI_InterlockedAdd64_acq:
6031 Ordering = llvm::AtomicOrdering::Acquire;
6032 break;
6033 case clang::AArch64::BI_InterlockedAdd_rel:
6034 case clang::AArch64::BI_InterlockedAdd64_rel:
6035 Ordering = llvm::AtomicOrdering::Release;
6036 break;
6037 case clang::AArch64::BI_InterlockedAdd_nf:
6038 case clang::AArch64::BI_InterlockedAdd64_nf:
6039 Ordering = llvm::AtomicOrdering::Monotonic;
6040 break;
6041 default:
6042 llvm_unreachable("missing builtin ID in switch!");
6043 }
6044 AtomicRMWInst *RMWI =
6045 Builder.CreateAtomicRMW(Op: AtomicRMWInst::Add, Addr: DestAddr, Val, Ordering);
6046 return Builder.CreateAdd(LHS: RMWI, RHS: Val);
6047 }
6048 }
6049
6050 llvm::FixedVectorType *VTy = GetNeonType(CGF: this, TypeFlags: Type);
6051 llvm::Type *Ty = VTy;
6052 if (!Ty)
6053 return nullptr;
6054
6055 bool ExtractLow = false;
6056 bool ExtendLaneArg = false;
6057 switch (BuiltinID) {
6058 default: return nullptr;
6059 case NEON::BI__builtin_neon_vbsl_v:
6060 case NEON::BI__builtin_neon_vbslq_v: {
6061 llvm::Type *BitTy = llvm::VectorType::getInteger(VTy);
6062 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: BitTy, Name: "vbsl");
6063 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: BitTy, Name: "vbsl");
6064 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: BitTy, Name: "vbsl");
6065
6066 Ops[1] = Builder.CreateAnd(LHS: Ops[0], RHS: Ops[1], Name: "vbsl");
6067 Ops[2] = Builder.CreateAnd(LHS: Builder.CreateNot(V: Ops[0]), RHS: Ops[2], Name: "vbsl");
6068 Ops[0] = Builder.CreateOr(LHS: Ops[1], RHS: Ops[2], Name: "vbsl");
6069 return Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
6070 }
6071 case NEON::BI__builtin_neon_vfma_lane_v:
6072 case NEON::BI__builtin_neon_vfmaq_lane_v: { // Only used for FP types
6073 // The ARM builtins (and instructions) have the addend as the first
6074 // operand, but the 'fma' intrinsics have it last. Swap it around here.
6075 Value *Addend = Ops[0];
6076 Value *Multiplicand = Ops[1];
6077 Value *LaneSource = Ops[2];
6078 Ops[0] = Multiplicand;
6079 Ops[1] = LaneSource;
6080 Ops[2] = Addend;
6081
6082 // Now adjust things to handle the lane access.
6083 auto *SourceTy = BuiltinID == NEON::BI__builtin_neon_vfmaq_lane_v
6084 ? llvm::FixedVectorType::get(ElementType: VTy->getElementType(),
6085 NumElts: VTy->getNumElements() / 2)
6086 : VTy;
6087 llvm::Constant *cst = cast<Constant>(Val: Ops[3]);
6088 Value *SV = llvm::ConstantVector::getSplat(EC: VTy->getElementCount(), Elt: cst);
6089 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: SourceTy);
6090 Ops[1] = Builder.CreateShuffleVector(V1: Ops[1], V2: Ops[1], Mask: SV, Name: "lane");
6091
6092 Ops.pop_back();
6093 Int = Builder.getIsFPConstrained() ? Intrinsic::experimental_constrained_fma
6094 : Intrinsic::fma;
6095 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "fmla");
6096 }
6097 case NEON::BI__builtin_neon_vfma_laneq_v: {
6098 auto *VTy = cast<llvm::FixedVectorType>(Val: Ty);
6099 // v1f64 fma should be mapped to Neon scalar f64 fma
6100 if (VTy && VTy->getElementType() == DoubleTy) {
6101 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: DoubleTy);
6102 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: DoubleTy);
6103 llvm::FixedVectorType *VTy =
6104 GetNeonType(CGF: this, TypeFlags: NeonTypeFlags(NeonTypeFlags::Float64, false, true));
6105 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: VTy);
6106 Ops[2] = Builder.CreateExtractElement(Vec: Ops[2], Idx: Ops[3], Name: "extract");
6107 Value *Result;
6108 Result = emitCallMaybeConstrainedFPBuiltin(
6109 CGF&: *this, IntrinsicID: Intrinsic::fma, ConstrainedIntrinsicID: Intrinsic::experimental_constrained_fma,
6110 Ty: DoubleTy, Args: {Ops[1], Ops[2], Ops[0]});
6111 return Builder.CreateBitCast(V: Result, DestTy: Ty);
6112 }
6113 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
6114 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
6115
6116 auto *STy = llvm::FixedVectorType::get(ElementType: VTy->getElementType(),
6117 NumElts: VTy->getNumElements() * 2);
6118 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: STy);
6119 Value *SV = llvm::ConstantVector::getSplat(EC: VTy->getElementCount(),
6120 Elt: cast<ConstantInt>(Val: Ops[3]));
6121 Ops[2] = Builder.CreateShuffleVector(V1: Ops[2], V2: Ops[2], Mask: SV, Name: "lane");
6122
6123 return emitCallMaybeConstrainedFPBuiltin(
6124 CGF&: *this, IntrinsicID: Intrinsic::fma, ConstrainedIntrinsicID: Intrinsic::experimental_constrained_fma, Ty,
6125 Args: {Ops[2], Ops[1], Ops[0]});
6126 }
6127 case NEON::BI__builtin_neon_vfmaq_laneq_v: {
6128 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
6129 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
6130
6131 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: Ty);
6132 Ops[2] = EmitNeonSplat(V: Ops[2], C: cast<ConstantInt>(Val: Ops[3]));
6133 return emitCallMaybeConstrainedFPBuiltin(
6134 CGF&: *this, IntrinsicID: Intrinsic::fma, ConstrainedIntrinsicID: Intrinsic::experimental_constrained_fma, Ty,
6135 Args: {Ops[2], Ops[1], Ops[0]});
6136 }
6137 case NEON::BI__builtin_neon_vfmah_lane_f16:
6138 case NEON::BI__builtin_neon_vfmas_lane_f32:
6139 case NEON::BI__builtin_neon_vfmah_laneq_f16:
6140 case NEON::BI__builtin_neon_vfmas_laneq_f32:
6141 case NEON::BI__builtin_neon_vfmad_lane_f64:
6142 case NEON::BI__builtin_neon_vfmad_laneq_f64: {
6143 llvm::Type *Ty = ConvertType(T: E->getCallReturnType(Ctx: getContext()));
6144 Ops[2] = Builder.CreateExtractElement(Vec: Ops[2], Idx: Ops[3], Name: "extract");
6145 return emitCallMaybeConstrainedFPBuiltin(
6146 CGF&: *this, IntrinsicID: Intrinsic::fma, ConstrainedIntrinsicID: Intrinsic::experimental_constrained_fma, Ty,
6147 Args: {Ops[1], Ops[2], Ops[0]});
6148 }
6149 case NEON::BI__builtin_neon_vmull_v:
6150 // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
6151 Int = usgn ? Intrinsic::aarch64_neon_umull : Intrinsic::aarch64_neon_smull;
6152 if (Type.isPoly()) Int = Intrinsic::aarch64_neon_pmull;
6153 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vmull");
6154 case NEON::BI__builtin_neon_vmax_v:
6155 case NEON::BI__builtin_neon_vmaxq_v:
6156 // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
6157 Int = usgn ? Intrinsic::aarch64_neon_umax : Intrinsic::aarch64_neon_smax;
6158 if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fmax;
6159 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vmax");
6160 case NEON::BI__builtin_neon_vmaxh_f16: {
6161 Int = Intrinsic::aarch64_neon_fmax;
6162 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vmax");
6163 }
6164 case NEON::BI__builtin_neon_vmin_v:
6165 case NEON::BI__builtin_neon_vminq_v:
6166 // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
6167 Int = usgn ? Intrinsic::aarch64_neon_umin : Intrinsic::aarch64_neon_smin;
6168 if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fmin;
6169 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vmin");
6170 case NEON::BI__builtin_neon_vminh_f16: {
6171 Int = Intrinsic::aarch64_neon_fmin;
6172 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vmin");
6173 }
6174 case NEON::BI__builtin_neon_vabd_v:
6175 case NEON::BI__builtin_neon_vabdq_v:
6176 // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
6177 Int = usgn ? Intrinsic::aarch64_neon_uabd : Intrinsic::aarch64_neon_sabd;
6178 if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fabd;
6179 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vabd");
6180 case NEON::BI__builtin_neon_vpadal_v:
6181 case NEON::BI__builtin_neon_vpadalq_v: {
6182 unsigned ArgElts = VTy->getNumElements();
6183 llvm::IntegerType *EltTy = cast<IntegerType>(Val: VTy->getElementType());
6184 unsigned BitWidth = EltTy->getBitWidth();
6185 auto *ArgTy = llvm::FixedVectorType::get(
6186 ElementType: llvm::IntegerType::get(C&: getLLVMContext(), NumBits: BitWidth / 2), NumElts: 2 * ArgElts);
6187 llvm::Type* Tys[2] = { VTy, ArgTy };
6188 Int = usgn ? Intrinsic::aarch64_neon_uaddlp : Intrinsic::aarch64_neon_saddlp;
6189 SmallVector<llvm::Value*, 1> TmpOps;
6190 TmpOps.push_back(Elt: Ops[1]);
6191 Function *F = CGM.getIntrinsic(IID: Int, Tys);
6192 llvm::Value *tmp = EmitNeonCall(F, Ops&: TmpOps, name: "vpadal");
6193 llvm::Value *addend = Builder.CreateBitCast(V: Ops[0], DestTy: tmp->getType());
6194 return Builder.CreateAdd(LHS: tmp, RHS: addend);
6195 }
6196 case NEON::BI__builtin_neon_vpmin_v:
6197 case NEON::BI__builtin_neon_vpminq_v:
6198 // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
6199 Int = usgn ? Intrinsic::aarch64_neon_uminp : Intrinsic::aarch64_neon_sminp;
6200 if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fminp;
6201 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vpmin");
6202 case NEON::BI__builtin_neon_vpmax_v:
6203 case NEON::BI__builtin_neon_vpmaxq_v:
6204 // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
6205 Int = usgn ? Intrinsic::aarch64_neon_umaxp : Intrinsic::aarch64_neon_smaxp;
6206 if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fmaxp;
6207 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vpmax");
6208 case NEON::BI__builtin_neon_vminnm_v:
6209 case NEON::BI__builtin_neon_vminnmq_v:
6210 Int = Intrinsic::aarch64_neon_fminnm;
6211 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vminnm");
6212 case NEON::BI__builtin_neon_vminnmh_f16:
6213 Int = Intrinsic::aarch64_neon_fminnm;
6214 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vminnm");
6215 case NEON::BI__builtin_neon_vmaxnm_v:
6216 case NEON::BI__builtin_neon_vmaxnmq_v:
6217 Int = Intrinsic::aarch64_neon_fmaxnm;
6218 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vmaxnm");
6219 case NEON::BI__builtin_neon_vmaxnmh_f16:
6220 Int = Intrinsic::aarch64_neon_fmaxnm;
6221 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vmaxnm");
6222 case NEON::BI__builtin_neon_vrecpss_f32: {
6223 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_frecps, Tys: FloatTy),
6224 Ops, name: "vrecps");
6225 }
6226 case NEON::BI__builtin_neon_vrecpsd_f64:
6227 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_frecps, Tys: DoubleTy),
6228 Ops, name: "vrecps");
6229 case NEON::BI__builtin_neon_vrecpsh_f16:
6230 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_frecps, Tys: HalfTy),
6231 Ops, name: "vrecps");
6232 case NEON::BI__builtin_neon_vqshrun_n_v:
6233 Int = Intrinsic::aarch64_neon_sqshrun;
6234 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vqshrun_n");
6235 case NEON::BI__builtin_neon_vqrshrun_n_v:
6236 Int = Intrinsic::aarch64_neon_sqrshrun;
6237 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vqrshrun_n");
6238 case NEON::BI__builtin_neon_vqshrn_n_v:
6239 Int = usgn ? Intrinsic::aarch64_neon_uqshrn : Intrinsic::aarch64_neon_sqshrn;
6240 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vqshrn_n");
6241 case NEON::BI__builtin_neon_vrshrn_n_v:
6242 Int = Intrinsic::aarch64_neon_rshrn;
6243 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vrshrn_n");
6244 case NEON::BI__builtin_neon_vqrshrn_n_v:
6245 Int = usgn ? Intrinsic::aarch64_neon_uqrshrn : Intrinsic::aarch64_neon_sqrshrn;
6246 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vqrshrn_n");
6247 case NEON::BI__builtin_neon_vrndah_f16: {
6248 Int = Builder.getIsFPConstrained()
6249 ? Intrinsic::experimental_constrained_round
6250 : Intrinsic::round;
6251 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vrnda");
6252 }
6253 case NEON::BI__builtin_neon_vrnda_v:
6254 case NEON::BI__builtin_neon_vrndaq_v: {
6255 Int = Builder.getIsFPConstrained()
6256 ? Intrinsic::experimental_constrained_round
6257 : Intrinsic::round;
6258 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vrnda");
6259 }
6260 case NEON::BI__builtin_neon_vrndih_f16: {
6261 Int = Builder.getIsFPConstrained()
6262 ? Intrinsic::experimental_constrained_nearbyint
6263 : Intrinsic::nearbyint;
6264 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vrndi");
6265 }
6266 case NEON::BI__builtin_neon_vrndmh_f16: {
6267 Int = Builder.getIsFPConstrained()
6268 ? Intrinsic::experimental_constrained_floor
6269 : Intrinsic::floor;
6270 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vrndm");
6271 }
6272 case NEON::BI__builtin_neon_vrndm_v:
6273 case NEON::BI__builtin_neon_vrndmq_v: {
6274 Int = Builder.getIsFPConstrained()
6275 ? Intrinsic::experimental_constrained_floor
6276 : Intrinsic::floor;
6277 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vrndm");
6278 }
6279 case NEON::BI__builtin_neon_vrndnh_f16: {
6280 Int = Builder.getIsFPConstrained()
6281 ? Intrinsic::experimental_constrained_roundeven
6282 : Intrinsic::roundeven;
6283 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vrndn");
6284 }
6285 case NEON::BI__builtin_neon_vrndn_v:
6286 case NEON::BI__builtin_neon_vrndnq_v: {
6287 Int = Builder.getIsFPConstrained()
6288 ? Intrinsic::experimental_constrained_roundeven
6289 : Intrinsic::roundeven;
6290 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vrndn");
6291 }
6292 case NEON::BI__builtin_neon_vrndns_f32: {
6293 Int = Builder.getIsFPConstrained()
6294 ? Intrinsic::experimental_constrained_roundeven
6295 : Intrinsic::roundeven;
6296 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: FloatTy), Ops, name: "vrndn");
6297 }
6298 case NEON::BI__builtin_neon_vrndph_f16: {
6299 Int = Builder.getIsFPConstrained()
6300 ? Intrinsic::experimental_constrained_ceil
6301 : Intrinsic::ceil;
6302 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vrndp");
6303 }
6304 case NEON::BI__builtin_neon_vrndp_v:
6305 case NEON::BI__builtin_neon_vrndpq_v: {
6306 Int = Builder.getIsFPConstrained()
6307 ? Intrinsic::experimental_constrained_ceil
6308 : Intrinsic::ceil;
6309 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vrndp");
6310 }
6311 case NEON::BI__builtin_neon_vrndxh_f16: {
6312 Int = Builder.getIsFPConstrained()
6313 ? Intrinsic::experimental_constrained_rint
6314 : Intrinsic::rint;
6315 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vrndx");
6316 }
6317 case NEON::BI__builtin_neon_vrndx_v:
6318 case NEON::BI__builtin_neon_vrndxq_v: {
6319 Int = Builder.getIsFPConstrained()
6320 ? Intrinsic::experimental_constrained_rint
6321 : Intrinsic::rint;
6322 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vrndx");
6323 }
6324 case NEON::BI__builtin_neon_vrndh_f16: {
6325 Int = Builder.getIsFPConstrained()
6326 ? Intrinsic::experimental_constrained_trunc
6327 : Intrinsic::trunc;
6328 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vrndz");
6329 }
6330 case NEON::BI__builtin_neon_vrnd_v:
6331 case NEON::BI__builtin_neon_vrndq_v: {
6332 Int = Builder.getIsFPConstrained()
6333 ? Intrinsic::experimental_constrained_trunc
6334 : Intrinsic::trunc;
6335 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vrndz");
6336 }
6337 case NEON::BI__builtin_neon_vcvt_f64_v:
6338 case NEON::BI__builtin_neon_vcvtq_f64_v:
6339 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
6340 Ty = GetNeonType(CGF: this, TypeFlags: NeonTypeFlags(NeonTypeFlags::Float64, false, quad));
6341 return usgn ? Builder.CreateUIToFP(V: Ops[0], DestTy: Ty, Name: "vcvt")
6342 : Builder.CreateSIToFP(V: Ops[0], DestTy: Ty, Name: "vcvt");
6343 case NEON::BI__builtin_neon_vcvt_f64_f32: {
6344 assert(Type.getEltType() == NeonTypeFlags::Float64 && quad &&
6345 "unexpected vcvt_f64_f32 builtin");
6346 NeonTypeFlags SrcFlag = NeonTypeFlags(NeonTypeFlags::Float32, false, false);
6347 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: GetNeonType(CGF: this, TypeFlags: SrcFlag));
6348
6349 return Builder.CreateFPExt(V: Ops[0], DestTy: Ty, Name: "vcvt");
6350 }
6351 case NEON::BI__builtin_neon_vcvt_f32_f64: {
6352 assert(Type.getEltType() == NeonTypeFlags::Float32 &&
6353 "unexpected vcvt_f32_f64 builtin");
6354 NeonTypeFlags SrcFlag = NeonTypeFlags(NeonTypeFlags::Float64, false, true);
6355 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: GetNeonType(CGF: this, TypeFlags: SrcFlag));
6356
6357 return Builder.CreateFPTrunc(V: Ops[0], DestTy: Ty, Name: "vcvt");
6358 }
6359 case NEON::BI__builtin_neon_vcvta_s16_f16:
6360 case NEON::BI__builtin_neon_vcvta_u16_f16:
6361 case NEON::BI__builtin_neon_vcvta_s32_v:
6362 case NEON::BI__builtin_neon_vcvtaq_s16_f16:
6363 case NEON::BI__builtin_neon_vcvtaq_s32_v:
6364 case NEON::BI__builtin_neon_vcvta_u32_v:
6365 case NEON::BI__builtin_neon_vcvtaq_u16_f16:
6366 case NEON::BI__builtin_neon_vcvtaq_u32_v:
6367 case NEON::BI__builtin_neon_vcvta_s64_v:
6368 case NEON::BI__builtin_neon_vcvtaq_s64_v:
6369 case NEON::BI__builtin_neon_vcvta_u64_v:
6370 case NEON::BI__builtin_neon_vcvtaq_u64_v: {
6371 Int = usgn ? Intrinsic::aarch64_neon_fcvtau : Intrinsic::aarch64_neon_fcvtas;
6372 llvm::Type *Tys[2] = { Ty, GetFloatNeonType(CGF: this, IntTypeFlags: Type) };
6373 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vcvta");
6374 }
6375 case NEON::BI__builtin_neon_vcvtm_s16_f16:
6376 case NEON::BI__builtin_neon_vcvtmq_s16_f16:
6377 case NEON::BI__builtin_neon_vcvtm_u16_f16:
6378 case NEON::BI__builtin_neon_vcvtmq_u16_f16:
6379 case NEON::BI__builtin_neon_vcvtm_s32_v:
6380 case NEON::BI__builtin_neon_vcvtmq_s32_v:
6381 case NEON::BI__builtin_neon_vcvtm_u32_v:
6382 case NEON::BI__builtin_neon_vcvtmq_u32_v:
6383 case NEON::BI__builtin_neon_vcvtm_s64_v:
6384 case NEON::BI__builtin_neon_vcvtmq_s64_v:
6385 case NEON::BI__builtin_neon_vcvtm_u64_v:
6386 case NEON::BI__builtin_neon_vcvtmq_u64_v: {
6387 Int = usgn ? Intrinsic::aarch64_neon_fcvtmu : Intrinsic::aarch64_neon_fcvtms;
6388 llvm::Type *Tys[2] = { Ty, GetFloatNeonType(CGF: this, IntTypeFlags: Type) };
6389 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vcvtm");
6390 }
6391 case NEON::BI__builtin_neon_vcvtn_s16_f16:
6392 case NEON::BI__builtin_neon_vcvtnq_s16_f16:
6393 case NEON::BI__builtin_neon_vcvtn_u16_f16:
6394 case NEON::BI__builtin_neon_vcvtnq_u16_f16:
6395 case NEON::BI__builtin_neon_vcvtn_s32_v:
6396 case NEON::BI__builtin_neon_vcvtnq_s32_v:
6397 case NEON::BI__builtin_neon_vcvtn_u32_v:
6398 case NEON::BI__builtin_neon_vcvtnq_u32_v:
6399 case NEON::BI__builtin_neon_vcvtn_s64_v:
6400 case NEON::BI__builtin_neon_vcvtnq_s64_v:
6401 case NEON::BI__builtin_neon_vcvtn_u64_v:
6402 case NEON::BI__builtin_neon_vcvtnq_u64_v: {
6403 Int = usgn ? Intrinsic::aarch64_neon_fcvtnu : Intrinsic::aarch64_neon_fcvtns;
6404 llvm::Type *Tys[2] = { Ty, GetFloatNeonType(CGF: this, IntTypeFlags: Type) };
6405 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vcvtn");
6406 }
6407 case NEON::BI__builtin_neon_vcvtp_s16_f16:
6408 case NEON::BI__builtin_neon_vcvtpq_s16_f16:
6409 case NEON::BI__builtin_neon_vcvtp_u16_f16:
6410 case NEON::BI__builtin_neon_vcvtpq_u16_f16:
6411 case NEON::BI__builtin_neon_vcvtp_s32_v:
6412 case NEON::BI__builtin_neon_vcvtpq_s32_v:
6413 case NEON::BI__builtin_neon_vcvtp_u32_v:
6414 case NEON::BI__builtin_neon_vcvtpq_u32_v:
6415 case NEON::BI__builtin_neon_vcvtp_s64_v:
6416 case NEON::BI__builtin_neon_vcvtpq_s64_v:
6417 case NEON::BI__builtin_neon_vcvtp_u64_v:
6418 case NEON::BI__builtin_neon_vcvtpq_u64_v: {
6419 Int = usgn ? Intrinsic::aarch64_neon_fcvtpu : Intrinsic::aarch64_neon_fcvtps;
6420 llvm::Type *Tys[2] = { Ty, GetFloatNeonType(CGF: this, IntTypeFlags: Type) };
6421 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vcvtp");
6422 }
6423 case NEON::BI__builtin_neon_vmulx_v:
6424 case NEON::BI__builtin_neon_vmulxq_v: {
6425 Int = Intrinsic::aarch64_neon_fmulx;
6426 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vmulx");
6427 }
6428 case NEON::BI__builtin_neon_vmulxh_lane_f16:
6429 case NEON::BI__builtin_neon_vmulxh_laneq_f16: {
6430 // vmulx_lane should be mapped to Neon scalar mulx after
6431 // extracting the scalar element
6432 Ops[1] = Builder.CreateExtractElement(Vec: Ops[1], Idx: Ops[2], Name: "extract");
6433 Ops.pop_back();
6434 Int = Intrinsic::aarch64_neon_fmulx;
6435 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vmulx");
6436 }
6437 case NEON::BI__builtin_neon_vmul_lane_v:
6438 case NEON::BI__builtin_neon_vmul_laneq_v: {
6439 // v1f64 vmul_lane should be mapped to Neon scalar mul lane
6440 bool Quad = false;
6441 if (BuiltinID == NEON::BI__builtin_neon_vmul_laneq_v)
6442 Quad = true;
6443 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: DoubleTy);
6444 llvm::FixedVectorType *VTy =
6445 GetNeonType(CGF: this, TypeFlags: NeonTypeFlags(NeonTypeFlags::Float64, false, Quad));
6446 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: VTy);
6447 Ops[1] = Builder.CreateExtractElement(Vec: Ops[1], Idx: Ops[2], Name: "extract");
6448 Value *Result = Builder.CreateFMul(L: Ops[0], R: Ops[1]);
6449 return Builder.CreateBitCast(V: Result, DestTy: Ty);
6450 }
6451 case NEON::BI__builtin_neon_vpmaxnm_v:
6452 case NEON::BI__builtin_neon_vpmaxnmq_v: {
6453 Int = Intrinsic::aarch64_neon_fmaxnmp;
6454 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vpmaxnm");
6455 }
6456 case NEON::BI__builtin_neon_vpminnm_v:
6457 case NEON::BI__builtin_neon_vpminnmq_v: {
6458 Int = Intrinsic::aarch64_neon_fminnmp;
6459 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vpminnm");
6460 }
6461 case NEON::BI__builtin_neon_vsqrth_f16: {
6462 Int = Builder.getIsFPConstrained()
6463 ? Intrinsic::experimental_constrained_sqrt
6464 : Intrinsic::sqrt;
6465 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: HalfTy), Ops, name: "vsqrt");
6466 }
6467 case NEON::BI__builtin_neon_vsqrt_v:
6468 case NEON::BI__builtin_neon_vsqrtq_v: {
6469 Int = Builder.getIsFPConstrained()
6470 ? Intrinsic::experimental_constrained_sqrt
6471 : Intrinsic::sqrt;
6472 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
6473 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vsqrt");
6474 }
6475 case NEON::BI__builtin_neon_vrbit_v:
6476 case NEON::BI__builtin_neon_vrbitq_v: {
6477 Int = Intrinsic::bitreverse;
6478 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vrbit");
6479 }
6480 case NEON::BI__builtin_neon_vmaxv_f16: {
6481 Int = Intrinsic::aarch64_neon_fmaxv;
6482 Ty = HalfTy;
6483 VTy = llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 4);
6484 llvm::Type *Tys[2] = {Ty, VTy};
6485 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vmaxv");
6486 }
6487 case NEON::BI__builtin_neon_vmaxvq_f16: {
6488 Int = Intrinsic::aarch64_neon_fmaxv;
6489 Ty = HalfTy;
6490 VTy = llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 8);
6491 llvm::Type *Tys[2] = {Ty, VTy};
6492 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vmaxv");
6493 }
6494 case NEON::BI__builtin_neon_vminv_f16: {
6495 Int = Intrinsic::aarch64_neon_fminv;
6496 Ty = HalfTy;
6497 VTy = llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 4);
6498 llvm::Type *Tys[2] = {Ty, VTy};
6499 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vminv");
6500 }
6501 case NEON::BI__builtin_neon_vminvq_f16: {
6502 Int = Intrinsic::aarch64_neon_fminv;
6503 Ty = HalfTy;
6504 VTy = llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 8);
6505 llvm::Type *Tys[2] = {Ty, VTy};
6506 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vminv");
6507 }
6508 case NEON::BI__builtin_neon_vmaxnmv_f16: {
6509 Int = Intrinsic::aarch64_neon_fmaxnmv;
6510 Ty = HalfTy;
6511 VTy = llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 4);
6512 llvm::Type *Tys[2] = {Ty, VTy};
6513 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vmaxnmv");
6514 }
6515 case NEON::BI__builtin_neon_vmaxnmvq_f16: {
6516 Int = Intrinsic::aarch64_neon_fmaxnmv;
6517 Ty = HalfTy;
6518 VTy = llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 8);
6519 llvm::Type *Tys[2] = {Ty, VTy};
6520 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vmaxnmv");
6521 }
6522 case NEON::BI__builtin_neon_vminnmv_f16: {
6523 Int = Intrinsic::aarch64_neon_fminnmv;
6524 Ty = HalfTy;
6525 VTy = llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 4);
6526 llvm::Type *Tys[2] = {Ty, VTy};
6527 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vminnmv");
6528 }
6529 case NEON::BI__builtin_neon_vminnmvq_f16: {
6530 Int = Intrinsic::aarch64_neon_fminnmv;
6531 Ty = HalfTy;
6532 VTy = llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 8);
6533 llvm::Type *Tys[2] = {Ty, VTy};
6534 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vminnmv");
6535 }
6536 case NEON::BI__builtin_neon_vmul_n_f64: {
6537 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: DoubleTy);
6538 Value *RHS = Builder.CreateBitCast(V: Ops[1], DestTy: DoubleTy);
6539 return Builder.CreateFMul(L: Ops[0], R: RHS);
6540 }
6541 case NEON::BI__builtin_neon_vaddlv_u8:
6542 case NEON::BI__builtin_neon_vaddlvq_u8:
6543 case NEON::BI__builtin_neon_vaddlv_u16:
6544 case NEON::BI__builtin_neon_vaddlvq_u16: {
6545 Int = Intrinsic::aarch64_neon_uaddlv;
6546 Ty = Int32Ty;
6547 VTy = cast<llvm::FixedVectorType>(Val: Ops[0]->getType());
6548 llvm::Type *Tys[2] = {Ty, VTy};
6549 Value *Result = EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vaddlv");
6550 if (VTy->getElementType()->getPrimitiveSizeInBits() == 8)
6551 return Builder.CreateTrunc(V: Result, DestTy: Int16Ty);
6552 return Result;
6553 }
6554 case NEON::BI__builtin_neon_vaddlv_s8:
6555 case NEON::BI__builtin_neon_vaddlvq_s8:
6556 case NEON::BI__builtin_neon_vaddlv_s16:
6557 case NEON::BI__builtin_neon_vaddlvq_s16: {
6558 Int = Intrinsic::aarch64_neon_saddlv;
6559 Ty = Int32Ty;
6560 VTy = cast<llvm::FixedVectorType>(Val: Ops[0]->getType());
6561 llvm::Type *Tys[2] = {Ty, VTy};
6562 Value *Result = EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vaddlv");
6563 if (VTy->getElementType()->getPrimitiveSizeInBits() == 8)
6564 return Builder.CreateTrunc(V: Result, DestTy: Int16Ty);
6565 return Result;
6566 }
6567 case NEON::BI__builtin_neon_vsri_n_v:
6568 case NEON::BI__builtin_neon_vsriq_n_v: {
6569 Int = Intrinsic::aarch64_neon_vsri;
6570 llvm::Function *Intrin = CGM.getIntrinsic(IID: Int, Tys: Ty);
6571 return EmitNeonCall(F: Intrin, Ops, name: "vsri_n");
6572 }
6573 case NEON::BI__builtin_neon_vsli_n_v:
6574 case NEON::BI__builtin_neon_vsliq_n_v: {
6575 Int = Intrinsic::aarch64_neon_vsli;
6576 llvm::Function *Intrin = CGM.getIntrinsic(IID: Int, Tys: Ty);
6577 return EmitNeonCall(F: Intrin, Ops, name: "vsli_n");
6578 }
6579 case NEON::BI__builtin_neon_vsra_n_v:
6580 case NEON::BI__builtin_neon_vsraq_n_v:
6581 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: Ty);
6582 Ops[1] = EmitNeonRShiftImm(Vec: Ops[1], Shift: Ops[2], Ty, usgn, name: "vsra_n");
6583 return Builder.CreateAdd(LHS: Ops[0], RHS: Ops[1]);
6584 case NEON::BI__builtin_neon_vrsra_n_v:
6585 case NEON::BI__builtin_neon_vrsraq_n_v: {
6586 Int = usgn ? Intrinsic::aarch64_neon_urshl : Intrinsic::aarch64_neon_srshl;
6587 SmallVector<llvm::Value*,2> TmpOps;
6588 TmpOps.push_back(Elt: Ops[1]);
6589 TmpOps.push_back(Elt: Ops[2]);
6590 Function* F = CGM.getIntrinsic(IID: Int, Tys: Ty);
6591 llvm::Value *tmp = EmitNeonCall(F, Ops&: TmpOps, name: "vrshr_n", shift: 1, rightshift: true);
6592 Ops[0] = Builder.CreateBitCast(V: Ops[0], DestTy: VTy);
6593 return Builder.CreateAdd(LHS: Ops[0], RHS: tmp);
6594 }
6595 case NEON::BI__builtin_neon_vld1_v:
6596 case NEON::BI__builtin_neon_vld1q_v: {
6597 return Builder.CreateAlignedLoad(Ty: VTy, Addr: Ops[0], Align: PtrOp0.getAlignment());
6598 }
6599 case NEON::BI__builtin_neon_vst1_v:
6600 case NEON::BI__builtin_neon_vst1q_v:
6601 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: VTy);
6602 return Builder.CreateAlignedStore(Val: Ops[1], Addr: Ops[0], Align: PtrOp0.getAlignment());
6603 case NEON::BI__builtin_neon_vld1_lane_v:
6604 case NEON::BI__builtin_neon_vld1q_lane_v: {
6605 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
6606 Ops[0] = Builder.CreateAlignedLoad(Ty: VTy->getElementType(), Addr: Ops[0],
6607 Align: PtrOp0.getAlignment());
6608 return Builder.CreateInsertElement(Vec: Ops[1], NewElt: Ops[0], Idx: Ops[2], Name: "vld1_lane");
6609 }
6610 case NEON::BI__builtin_neon_vldap1_lane_s64:
6611 case NEON::BI__builtin_neon_vldap1q_lane_s64: {
6612 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
6613 llvm::LoadInst *LI = Builder.CreateAlignedLoad(
6614 Ty: VTy->getElementType(), Addr: Ops[0], Align: PtrOp0.getAlignment());
6615 LI->setAtomic(Ordering: llvm::AtomicOrdering::Acquire);
6616 Ops[0] = LI;
6617 return Builder.CreateInsertElement(Vec: Ops[1], NewElt: Ops[0], Idx: Ops[2], Name: "vldap1_lane");
6618 }
6619 case NEON::BI__builtin_neon_vld1_dup_v:
6620 case NEON::BI__builtin_neon_vld1q_dup_v: {
6621 Value *V = PoisonValue::get(T: Ty);
6622 Ops[0] = Builder.CreateAlignedLoad(Ty: VTy->getElementType(), Addr: Ops[0],
6623 Align: PtrOp0.getAlignment());
6624 llvm::Constant *CI = ConstantInt::get(Ty: Int32Ty, V: 0);
6625 Ops[0] = Builder.CreateInsertElement(Vec: V, NewElt: Ops[0], Idx: CI);
6626 return EmitNeonSplat(V: Ops[0], C: CI);
6627 }
6628 case NEON::BI__builtin_neon_vst1_lane_v:
6629 case NEON::BI__builtin_neon_vst1q_lane_v:
6630 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
6631 Ops[1] = Builder.CreateExtractElement(Vec: Ops[1], Idx: Ops[2]);
6632 return Builder.CreateAlignedStore(Val: Ops[1], Addr: Ops[0], Align: PtrOp0.getAlignment());
6633 case NEON::BI__builtin_neon_vstl1_lane_s64:
6634 case NEON::BI__builtin_neon_vstl1q_lane_s64: {
6635 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
6636 Ops[1] = Builder.CreateExtractElement(Vec: Ops[1], Idx: Ops[2]);
6637 llvm::StoreInst *SI =
6638 Builder.CreateAlignedStore(Val: Ops[1], Addr: Ops[0], Align: PtrOp0.getAlignment());
6639 SI->setAtomic(Ordering: llvm::AtomicOrdering::Release);
6640 return SI;
6641 }
6642 case NEON::BI__builtin_neon_vld2_v:
6643 case NEON::BI__builtin_neon_vld2q_v: {
6644 llvm::Type *Tys[2] = {VTy, DefaultPtrTy};
6645 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_ld2, Tys);
6646 Ops[1] = Builder.CreateCall(Callee: F, Args: Ops[1], Name: "vld2");
6647 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
6648 }
6649 case NEON::BI__builtin_neon_vld3_v:
6650 case NEON::BI__builtin_neon_vld3q_v: {
6651 llvm::Type *Tys[2] = {VTy, DefaultPtrTy};
6652 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_ld3, Tys);
6653 Ops[1] = Builder.CreateCall(Callee: F, Args: Ops[1], Name: "vld3");
6654 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
6655 }
6656 case NEON::BI__builtin_neon_vld4_v:
6657 case NEON::BI__builtin_neon_vld4q_v: {
6658 llvm::Type *Tys[2] = {VTy, DefaultPtrTy};
6659 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_ld4, Tys);
6660 Ops[1] = Builder.CreateCall(Callee: F, Args: Ops[1], Name: "vld4");
6661 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
6662 }
6663 case NEON::BI__builtin_neon_vld2_dup_v:
6664 case NEON::BI__builtin_neon_vld2q_dup_v: {
6665 llvm::Type *Tys[2] = {VTy, DefaultPtrTy};
6666 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_ld2r, Tys);
6667 Ops[1] = Builder.CreateCall(Callee: F, Args: Ops[1], Name: "vld2");
6668 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
6669 }
6670 case NEON::BI__builtin_neon_vld3_dup_v:
6671 case NEON::BI__builtin_neon_vld3q_dup_v: {
6672 llvm::Type *Tys[2] = {VTy, DefaultPtrTy};
6673 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_ld3r, Tys);
6674 Ops[1] = Builder.CreateCall(Callee: F, Args: Ops[1], Name: "vld3");
6675 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
6676 }
6677 case NEON::BI__builtin_neon_vld4_dup_v:
6678 case NEON::BI__builtin_neon_vld4q_dup_v: {
6679 llvm::Type *Tys[2] = {VTy, DefaultPtrTy};
6680 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_ld4r, Tys);
6681 Ops[1] = Builder.CreateCall(Callee: F, Args: Ops[1], Name: "vld4");
6682 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
6683 }
6684 case NEON::BI__builtin_neon_vld2_lane_v:
6685 case NEON::BI__builtin_neon_vld2q_lane_v: {
6686 llvm::Type *Tys[2] = { VTy, Ops[1]->getType() };
6687 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_ld2lane, Tys);
6688 std::rotate(first: Ops.begin() + 1, middle: Ops.begin() + 2, last: Ops.end());
6689 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
6690 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: Ty);
6691 Ops[3] = Builder.CreateZExt(V: Ops[3], DestTy: Int64Ty);
6692 Ops[1] = Builder.CreateCall(Callee: F, Args: ArrayRef(Ops).slice(N: 1), Name: "vld2_lane");
6693 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
6694 }
6695 case NEON::BI__builtin_neon_vld3_lane_v:
6696 case NEON::BI__builtin_neon_vld3q_lane_v: {
6697 llvm::Type *Tys[2] = { VTy, Ops[1]->getType() };
6698 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_ld3lane, Tys);
6699 std::rotate(first: Ops.begin() + 1, middle: Ops.begin() + 2, last: Ops.end());
6700 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
6701 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: Ty);
6702 Ops[3] = Builder.CreateBitCast(V: Ops[3], DestTy: Ty);
6703 Ops[4] = Builder.CreateZExt(V: Ops[4], DestTy: Int64Ty);
6704 Ops[1] = Builder.CreateCall(Callee: F, Args: ArrayRef(Ops).slice(N: 1), Name: "vld3_lane");
6705 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
6706 }
6707 case NEON::BI__builtin_neon_vld4_lane_v:
6708 case NEON::BI__builtin_neon_vld4q_lane_v: {
6709 llvm::Type *Tys[2] = { VTy, Ops[1]->getType() };
6710 Function *F = CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_ld4lane, Tys);
6711 std::rotate(first: Ops.begin() + 1, middle: Ops.begin() + 2, last: Ops.end());
6712 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
6713 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: Ty);
6714 Ops[3] = Builder.CreateBitCast(V: Ops[3], DestTy: Ty);
6715 Ops[4] = Builder.CreateBitCast(V: Ops[4], DestTy: Ty);
6716 Ops[5] = Builder.CreateZExt(V: Ops[5], DestTy: Int64Ty);
6717 Ops[1] = Builder.CreateCall(Callee: F, Args: ArrayRef(Ops).slice(N: 1), Name: "vld4_lane");
6718 return Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
6719 }
6720 case NEON::BI__builtin_neon_vst2_v:
6721 case NEON::BI__builtin_neon_vst2q_v: {
6722 std::rotate(first: Ops.begin(), middle: Ops.begin() + 1, last: Ops.end());
6723 llvm::Type *Tys[2] = { VTy, Ops[2]->getType() };
6724 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_st2, Tys),
6725 Ops, name: "");
6726 }
6727 case NEON::BI__builtin_neon_vst2_lane_v:
6728 case NEON::BI__builtin_neon_vst2q_lane_v: {
6729 std::rotate(first: Ops.begin(), middle: Ops.begin() + 1, last: Ops.end());
6730 Ops[2] = Builder.CreateZExt(V: Ops[2], DestTy: Int64Ty);
6731 llvm::Type *Tys[2] = { VTy, Ops[3]->getType() };
6732 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_st2lane, Tys),
6733 Ops, name: "");
6734 }
6735 case NEON::BI__builtin_neon_vst3_v:
6736 case NEON::BI__builtin_neon_vst3q_v: {
6737 std::rotate(first: Ops.begin(), middle: Ops.begin() + 1, last: Ops.end());
6738 llvm::Type *Tys[2] = { VTy, Ops[3]->getType() };
6739 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_st3, Tys),
6740 Ops, name: "");
6741 }
6742 case NEON::BI__builtin_neon_vst3_lane_v:
6743 case NEON::BI__builtin_neon_vst3q_lane_v: {
6744 std::rotate(first: Ops.begin(), middle: Ops.begin() + 1, last: Ops.end());
6745 Ops[3] = Builder.CreateZExt(V: Ops[3], DestTy: Int64Ty);
6746 llvm::Type *Tys[2] = { VTy, Ops[4]->getType() };
6747 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_st3lane, Tys),
6748 Ops, name: "");
6749 }
6750 case NEON::BI__builtin_neon_vst4_v:
6751 case NEON::BI__builtin_neon_vst4q_v: {
6752 std::rotate(first: Ops.begin(), middle: Ops.begin() + 1, last: Ops.end());
6753 llvm::Type *Tys[2] = { VTy, Ops[4]->getType() };
6754 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_st4, Tys),
6755 Ops, name: "");
6756 }
6757 case NEON::BI__builtin_neon_vst4_lane_v:
6758 case NEON::BI__builtin_neon_vst4q_lane_v: {
6759 std::rotate(first: Ops.begin(), middle: Ops.begin() + 1, last: Ops.end());
6760 Ops[4] = Builder.CreateZExt(V: Ops[4], DestTy: Int64Ty);
6761 llvm::Type *Tys[2] = { VTy, Ops[5]->getType() };
6762 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_st4lane, Tys),
6763 Ops, name: "");
6764 }
6765 case NEON::BI__builtin_neon_vtrn_v:
6766 case NEON::BI__builtin_neon_vtrnq_v: {
6767 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
6768 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: Ty);
6769 Value *SV = nullptr;
6770
6771 for (unsigned vi = 0; vi != 2; ++vi) {
6772 SmallVector<int, 16> Indices;
6773 for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
6774 Indices.push_back(Elt: i+vi);
6775 Indices.push_back(Elt: i+e+vi);
6776 }
6777 Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ptr: Ops[0], Idx0: vi);
6778 SV = Builder.CreateShuffleVector(V1: Ops[1], V2: Ops[2], Mask: Indices, Name: "vtrn");
6779 SV = Builder.CreateDefaultAlignedStore(Val: SV, Addr);
6780 }
6781 return SV;
6782 }
6783 case NEON::BI__builtin_neon_vuzp_v:
6784 case NEON::BI__builtin_neon_vuzpq_v: {
6785 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
6786 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: Ty);
6787 Value *SV = nullptr;
6788
6789 for (unsigned vi = 0; vi != 2; ++vi) {
6790 SmallVector<int, 16> Indices;
6791 for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
6792 Indices.push_back(Elt: 2*i+vi);
6793
6794 Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ptr: Ops[0], Idx0: vi);
6795 SV = Builder.CreateShuffleVector(V1: Ops[1], V2: Ops[2], Mask: Indices, Name: "vuzp");
6796 SV = Builder.CreateDefaultAlignedStore(Val: SV, Addr);
6797 }
6798 return SV;
6799 }
6800 case NEON::BI__builtin_neon_vzip_v:
6801 case NEON::BI__builtin_neon_vzipq_v: {
6802 Ops[1] = Builder.CreateBitCast(V: Ops[1], DestTy: Ty);
6803 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: Ty);
6804 Value *SV = nullptr;
6805
6806 for (unsigned vi = 0; vi != 2; ++vi) {
6807 SmallVector<int, 16> Indices;
6808 for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
6809 Indices.push_back(Elt: (i + vi*e) >> 1);
6810 Indices.push_back(Elt: ((i + vi*e) >> 1)+e);
6811 }
6812 Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ptr: Ops[0], Idx0: vi);
6813 SV = Builder.CreateShuffleVector(V1: Ops[1], V2: Ops[2], Mask: Indices, Name: "vzip");
6814 SV = Builder.CreateDefaultAlignedStore(Val: SV, Addr);
6815 }
6816 return SV;
6817 }
6818 case NEON::BI__builtin_neon_vqtbl1q_v: {
6819 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_tbl1, Tys: Ty),
6820 Ops, name: "vtbl1");
6821 }
6822 case NEON::BI__builtin_neon_vqtbl2q_v: {
6823 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_tbl2, Tys: Ty),
6824 Ops, name: "vtbl2");
6825 }
6826 case NEON::BI__builtin_neon_vqtbl3q_v: {
6827 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_tbl3, Tys: Ty),
6828 Ops, name: "vtbl3");
6829 }
6830 case NEON::BI__builtin_neon_vqtbl4q_v: {
6831 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_tbl4, Tys: Ty),
6832 Ops, name: "vtbl4");
6833 }
6834 case NEON::BI__builtin_neon_vqtbx1q_v: {
6835 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_tbx1, Tys: Ty),
6836 Ops, name: "vtbx1");
6837 }
6838 case NEON::BI__builtin_neon_vqtbx2q_v: {
6839 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_tbx2, Tys: Ty),
6840 Ops, name: "vtbx2");
6841 }
6842 case NEON::BI__builtin_neon_vqtbx3q_v: {
6843 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_tbx3, Tys: Ty),
6844 Ops, name: "vtbx3");
6845 }
6846 case NEON::BI__builtin_neon_vqtbx4q_v: {
6847 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_tbx4, Tys: Ty),
6848 Ops, name: "vtbx4");
6849 }
6850 case NEON::BI__builtin_neon_vsqadd_v:
6851 case NEON::BI__builtin_neon_vsqaddq_v: {
6852 Int = Intrinsic::aarch64_neon_usqadd;
6853 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vsqadd");
6854 }
6855 case NEON::BI__builtin_neon_vuqadd_v:
6856 case NEON::BI__builtin_neon_vuqaddq_v: {
6857 Int = Intrinsic::aarch64_neon_suqadd;
6858 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vuqadd");
6859 }
6860
6861 case NEON::BI__builtin_neon_vluti2_laneq_mf8:
6862 case NEON::BI__builtin_neon_vluti2_laneq_bf16:
6863 case NEON::BI__builtin_neon_vluti2_laneq_f16:
6864 case NEON::BI__builtin_neon_vluti2_laneq_p16:
6865 case NEON::BI__builtin_neon_vluti2_laneq_p8:
6866 case NEON::BI__builtin_neon_vluti2_laneq_s16:
6867 case NEON::BI__builtin_neon_vluti2_laneq_s8:
6868 case NEON::BI__builtin_neon_vluti2_laneq_u16:
6869 case NEON::BI__builtin_neon_vluti2_laneq_u8: {
6870 Int = Intrinsic::aarch64_neon_vluti2_laneq;
6871 llvm::Type *Tys[2];
6872 Tys[0] = Ty;
6873 Tys[1] = GetNeonType(CGF: this, TypeFlags: NeonTypeFlags(Type.getEltType(), false,
6874 /*isQuad*/ false));
6875 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vluti2_laneq");
6876 }
6877 case NEON::BI__builtin_neon_vluti2q_laneq_mf8:
6878 case NEON::BI__builtin_neon_vluti2q_laneq_bf16:
6879 case NEON::BI__builtin_neon_vluti2q_laneq_f16:
6880 case NEON::BI__builtin_neon_vluti2q_laneq_p16:
6881 case NEON::BI__builtin_neon_vluti2q_laneq_p8:
6882 case NEON::BI__builtin_neon_vluti2q_laneq_s16:
6883 case NEON::BI__builtin_neon_vluti2q_laneq_s8:
6884 case NEON::BI__builtin_neon_vluti2q_laneq_u16:
6885 case NEON::BI__builtin_neon_vluti2q_laneq_u8: {
6886 Int = Intrinsic::aarch64_neon_vluti2_laneq;
6887 llvm::Type *Tys[2];
6888 Tys[0] = Ty;
6889 Tys[1] = GetNeonType(CGF: this, TypeFlags: NeonTypeFlags(Type.getEltType(), false,
6890 /*isQuad*/ true));
6891 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vluti2_laneq");
6892 }
6893 case NEON::BI__builtin_neon_vluti2_lane_mf8:
6894 case NEON::BI__builtin_neon_vluti2_lane_bf16:
6895 case NEON::BI__builtin_neon_vluti2_lane_f16:
6896 case NEON::BI__builtin_neon_vluti2_lane_p16:
6897 case NEON::BI__builtin_neon_vluti2_lane_p8:
6898 case NEON::BI__builtin_neon_vluti2_lane_s16:
6899 case NEON::BI__builtin_neon_vluti2_lane_s8:
6900 case NEON::BI__builtin_neon_vluti2_lane_u16:
6901 case NEON::BI__builtin_neon_vluti2_lane_u8: {
6902 Int = Intrinsic::aarch64_neon_vluti2_lane;
6903 llvm::Type *Tys[2];
6904 Tys[0] = Ty;
6905 Tys[1] = GetNeonType(CGF: this, TypeFlags: NeonTypeFlags(Type.getEltType(), false,
6906 /*isQuad*/ false));
6907 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vluti2_lane");
6908 }
6909 case NEON::BI__builtin_neon_vluti2q_lane_mf8:
6910 case NEON::BI__builtin_neon_vluti2q_lane_bf16:
6911 case NEON::BI__builtin_neon_vluti2q_lane_f16:
6912 case NEON::BI__builtin_neon_vluti2q_lane_p16:
6913 case NEON::BI__builtin_neon_vluti2q_lane_p8:
6914 case NEON::BI__builtin_neon_vluti2q_lane_s16:
6915 case NEON::BI__builtin_neon_vluti2q_lane_s8:
6916 case NEON::BI__builtin_neon_vluti2q_lane_u16:
6917 case NEON::BI__builtin_neon_vluti2q_lane_u8: {
6918 Int = Intrinsic::aarch64_neon_vluti2_lane;
6919 llvm::Type *Tys[2];
6920 Tys[0] = Ty;
6921 Tys[1] = GetNeonType(CGF: this, TypeFlags: NeonTypeFlags(Type.getEltType(), false,
6922 /*isQuad*/ true));
6923 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys), Ops, name: "vluti2_lane");
6924 }
6925 case NEON::BI__builtin_neon_vluti4q_lane_mf8:
6926 case NEON::BI__builtin_neon_vluti4q_lane_p8:
6927 case NEON::BI__builtin_neon_vluti4q_lane_s8:
6928 case NEON::BI__builtin_neon_vluti4q_lane_u8: {
6929 Int = Intrinsic::aarch64_neon_vluti4q_lane;
6930 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vluti4q_lane");
6931 }
6932 case NEON::BI__builtin_neon_vluti4q_laneq_mf8:
6933 case NEON::BI__builtin_neon_vluti4q_laneq_p8:
6934 case NEON::BI__builtin_neon_vluti4q_laneq_s8:
6935 case NEON::BI__builtin_neon_vluti4q_laneq_u8: {
6936 Int = Intrinsic::aarch64_neon_vluti4q_laneq;
6937 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vluti4q_laneq");
6938 }
6939 case NEON::BI__builtin_neon_vluti4q_lane_bf16_x2:
6940 case NEON::BI__builtin_neon_vluti4q_lane_f16_x2:
6941 case NEON::BI__builtin_neon_vluti4q_lane_p16_x2:
6942 case NEON::BI__builtin_neon_vluti4q_lane_s16_x2:
6943 case NEON::BI__builtin_neon_vluti4q_lane_u16_x2: {
6944 Int = Intrinsic::aarch64_neon_vluti4q_lane_x2;
6945 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vluti4q_lane_x2");
6946 }
6947 case NEON::BI__builtin_neon_vluti4q_laneq_bf16_x2:
6948 case NEON::BI__builtin_neon_vluti4q_laneq_f16_x2:
6949 case NEON::BI__builtin_neon_vluti4q_laneq_p16_x2:
6950 case NEON::BI__builtin_neon_vluti4q_laneq_s16_x2:
6951 case NEON::BI__builtin_neon_vluti4q_laneq_u16_x2: {
6952 Int = Intrinsic::aarch64_neon_vluti4q_laneq_x2;
6953 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "vluti4q_laneq_x2");
6954 }
6955 case NEON::BI__builtin_neon_vmmlaq_f16_mf8_fpm:
6956 return EmitFP8NeonCall(IID: Intrinsic::aarch64_neon_fmmla,
6957 Tys: {llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 8),
6958 llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: 16)},
6959 Ops, E, name: "fmmla");
6960 case NEON::BI__builtin_neon_vmmlaq_f32_mf8_fpm:
6961 return EmitFP8NeonCall(IID: Intrinsic::aarch64_neon_fmmla,
6962 Tys: {llvm::FixedVectorType::get(ElementType: FloatTy, NumElts: 4),
6963 llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: 16)},
6964 Ops, E, name: "fmmla");
6965 case NEON::BI__builtin_neon_vcvt1_low_bf16_mf8_fpm:
6966 ExtractLow = true;
6967 [[fallthrough]];
6968 case NEON::BI__builtin_neon_vcvt1_bf16_mf8_fpm:
6969 case NEON::BI__builtin_neon_vcvt1_high_bf16_mf8_fpm:
6970 return EmitFP8NeonCvtCall(IID: Intrinsic::aarch64_neon_fp8_cvtl1,
6971 Ty0: llvm::FixedVectorType::get(ElementType: BFloatTy, NumElts: 8),
6972 Ty1: Ops[0]->getType(), Extract: ExtractLow, Ops, E, name: "vbfcvt1");
6973 case NEON::BI__builtin_neon_vcvt2_low_bf16_mf8_fpm:
6974 ExtractLow = true;
6975 [[fallthrough]];
6976 case NEON::BI__builtin_neon_vcvt2_bf16_mf8_fpm:
6977 case NEON::BI__builtin_neon_vcvt2_high_bf16_mf8_fpm:
6978 return EmitFP8NeonCvtCall(IID: Intrinsic::aarch64_neon_fp8_cvtl2,
6979 Ty0: llvm::FixedVectorType::get(ElementType: BFloatTy, NumElts: 8),
6980 Ty1: Ops[0]->getType(), Extract: ExtractLow, Ops, E, name: "vbfcvt2");
6981 case NEON::BI__builtin_neon_vcvt1_low_f16_mf8_fpm:
6982 ExtractLow = true;
6983 [[fallthrough]];
6984 case NEON::BI__builtin_neon_vcvt1_f16_mf8_fpm:
6985 case NEON::BI__builtin_neon_vcvt1_high_f16_mf8_fpm:
6986 return EmitFP8NeonCvtCall(IID: Intrinsic::aarch64_neon_fp8_cvtl1,
6987 Ty0: llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 8),
6988 Ty1: Ops[0]->getType(), Extract: ExtractLow, Ops, E, name: "vbfcvt1");
6989 case NEON::BI__builtin_neon_vcvt2_low_f16_mf8_fpm:
6990 ExtractLow = true;
6991 [[fallthrough]];
6992 case NEON::BI__builtin_neon_vcvt2_f16_mf8_fpm:
6993 case NEON::BI__builtin_neon_vcvt2_high_f16_mf8_fpm:
6994 return EmitFP8NeonCvtCall(IID: Intrinsic::aarch64_neon_fp8_cvtl2,
6995 Ty0: llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 8),
6996 Ty1: Ops[0]->getType(), Extract: ExtractLow, Ops, E, name: "vbfcvt2");
6997 case NEON::BI__builtin_neon_vcvt_mf8_f32_fpm:
6998 return EmitFP8NeonCvtCall(IID: Intrinsic::aarch64_neon_fp8_fcvtn,
6999 Ty0: llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: 8),
7000 Ty1: Ops[0]->getType(), Extract: false, Ops, E, name: "vfcvtn");
7001 case NEON::BI__builtin_neon_vcvt_mf8_f16_fpm:
7002 return EmitFP8NeonCvtCall(IID: Intrinsic::aarch64_neon_fp8_fcvtn,
7003 Ty0: llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: 8),
7004 Ty1: llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 4), Extract: false, Ops,
7005 E, name: "vfcvtn");
7006 case NEON::BI__builtin_neon_vcvtq_mf8_f16_fpm:
7007 return EmitFP8NeonCvtCall(IID: Intrinsic::aarch64_neon_fp8_fcvtn,
7008 Ty0: llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: 16),
7009 Ty1: llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 8), Extract: false, Ops,
7010 E, name: "vfcvtn");
7011 case NEON::BI__builtin_neon_vcvt_high_mf8_f32_fpm: {
7012 llvm::Type *Ty = llvm::FixedVectorType::get(ElementType: Int8Ty, NumElts: 16);
7013 Ops[0] = Builder.CreateInsertVector(DstType: Ty, SrcVec: PoisonValue::get(T: Ty), SubVec: Ops[0],
7014 Idx: uint64_t(0));
7015 return EmitFP8NeonCvtCall(IID: Intrinsic::aarch64_neon_fp8_fcvtn2, Ty0: Ty,
7016 Ty1: Ops[1]->getType(), Extract: false, Ops, E, name: "vfcvtn2");
7017 }
7018
7019 case NEON::BI__builtin_neon_vdot_f16_mf8_fpm:
7020 case NEON::BI__builtin_neon_vdotq_f16_mf8_fpm:
7021 return EmitFP8NeonFDOTCall(IID: Intrinsic::aarch64_neon_fp8_fdot2, ExtendLaneArg: false, RetTy: HalfTy,
7022 Ops, E, name: "fdot2");
7023 case NEON::BI__builtin_neon_vdot_lane_f16_mf8_fpm:
7024 case NEON::BI__builtin_neon_vdotq_lane_f16_mf8_fpm:
7025 ExtendLaneArg = true;
7026 [[fallthrough]];
7027 case NEON::BI__builtin_neon_vdot_laneq_f16_mf8_fpm:
7028 case NEON::BI__builtin_neon_vdotq_laneq_f16_mf8_fpm:
7029 return EmitFP8NeonFDOTCall(IID: Intrinsic::aarch64_neon_fp8_fdot2_lane,
7030 ExtendLaneArg, RetTy: HalfTy, Ops, E, name: "fdot2_lane");
7031 case NEON::BI__builtin_neon_vdot_f32_mf8_fpm:
7032 case NEON::BI__builtin_neon_vdotq_f32_mf8_fpm:
7033 return EmitFP8NeonFDOTCall(IID: Intrinsic::aarch64_neon_fp8_fdot4, ExtendLaneArg: false,
7034 RetTy: FloatTy, Ops, E, name: "fdot4");
7035 case NEON::BI__builtin_neon_vdot_lane_f32_mf8_fpm:
7036 case NEON::BI__builtin_neon_vdotq_lane_f32_mf8_fpm:
7037 ExtendLaneArg = true;
7038 [[fallthrough]];
7039 case NEON::BI__builtin_neon_vdot_laneq_f32_mf8_fpm:
7040 case NEON::BI__builtin_neon_vdotq_laneq_f32_mf8_fpm:
7041 return EmitFP8NeonFDOTCall(IID: Intrinsic::aarch64_neon_fp8_fdot4_lane,
7042 ExtendLaneArg, RetTy: FloatTy, Ops, E, name: "fdot4_lane");
7043
7044 case NEON::BI__builtin_neon_vdot_f32_f16:
7045 case NEON::BI__builtin_neon_vdotq_f32_f16: {
7046 llvm::Type *InputTy =
7047 llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: Ty->getPrimitiveSizeInBits() / 16);
7048 llvm::Type *Tys[2] = {Ty, InputTy};
7049 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_fdot, Tys),
7050 Ops, name: "vdot");
7051 }
7052
7053 case NEON::BI__builtin_neon_vdot_lane_f32_f16:
7054 case NEON::BI__builtin_neon_vdot_laneq_f32_f16:
7055 case NEON::BI__builtin_neon_vdotq_lane_f32_f16:
7056 case NEON::BI__builtin_neon_vdotq_laneq_f32_f16: {
7057 llvm::FixedVectorType *InputTy =
7058 llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: Ty->getPrimitiveSizeInBits() / 16);
7059 llvm::FixedVectorType *LaneTy = llvm::FixedVectorType::get(
7060 ElementType: HalfTy, NumElts: Ops[2]->getType()->getPrimitiveSizeInBits() / 16);
7061 // Treat the lane argument as a splat and use non-lane version of the
7062 // intrinsic.
7063 Ops[2] = Builder.CreateBitCast(V: Ops[2], DestTy: LaneTy);
7064 Ops[2] = EmitNeonSplat(V: Ops[2], C: cast<ConstantInt>(Val: Ops[3]),
7065 Count: InputTy->getElementCount());
7066 llvm::Type *Tys[2] = {Ty, InputTy};
7067 Ops.pop_back();
7068 return EmitNeonCall(F: CGM.getIntrinsic(IID: Intrinsic::aarch64_neon_fdot, Tys),
7069 Ops, name: "vdot");
7070 }
7071
7072 case NEON::BI__builtin_neon_vmlalbq_f16_mf8_fpm:
7073 return EmitFP8NeonCall(IID: Intrinsic::aarch64_neon_fp8_fmlalb,
7074 Tys: {llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 8)}, Ops, E,
7075 name: "vmlal");
7076 case NEON::BI__builtin_neon_vmlaltq_f16_mf8_fpm:
7077 return EmitFP8NeonCall(IID: Intrinsic::aarch64_neon_fp8_fmlalt,
7078 Tys: {llvm::FixedVectorType::get(ElementType: HalfTy, NumElts: 8)}, Ops, E,
7079 name: "vmlal");
7080 case NEON::BI__builtin_neon_vmlallbbq_f32_mf8_fpm:
7081 return EmitFP8NeonCall(IID: Intrinsic::aarch64_neon_fp8_fmlallbb,
7082 Tys: {llvm::FixedVectorType::get(ElementType: FloatTy, NumElts: 4)}, Ops, E,
7083 name: "vmlall");
7084 case NEON::BI__builtin_neon_vmlallbtq_f32_mf8_fpm:
7085 return EmitFP8NeonCall(IID: Intrinsic::aarch64_neon_fp8_fmlallbt,
7086 Tys: {llvm::FixedVectorType::get(ElementType: FloatTy, NumElts: 4)}, Ops, E,
7087 name: "vmlall");
7088 case NEON::BI__builtin_neon_vmlalltbq_f32_mf8_fpm:
7089 return EmitFP8NeonCall(IID: Intrinsic::aarch64_neon_fp8_fmlalltb,
7090 Tys: {llvm::FixedVectorType::get(ElementType: FloatTy, NumElts: 4)}, Ops, E,
7091 name: "vmlall");
7092 case NEON::BI__builtin_neon_vmlallttq_f32_mf8_fpm:
7093 return EmitFP8NeonCall(IID: Intrinsic::aarch64_neon_fp8_fmlalltt,
7094 Tys: {llvm::FixedVectorType::get(ElementType: FloatTy, NumElts: 4)}, Ops, E,
7095 name: "vmlall");
7096 case NEON::BI__builtin_neon_vmlalbq_lane_f16_mf8_fpm:
7097 ExtendLaneArg = true;
7098 [[fallthrough]];
7099 case NEON::BI__builtin_neon_vmlalbq_laneq_f16_mf8_fpm:
7100 return EmitFP8NeonFMLACall(IID: Intrinsic::aarch64_neon_fp8_fmlalb_lane,
7101 ExtendLaneArg, RetTy: HalfTy, Ops, E, name: "vmlal_lane");
7102 case NEON::BI__builtin_neon_vmlaltq_lane_f16_mf8_fpm:
7103 ExtendLaneArg = true;
7104 [[fallthrough]];
7105 case NEON::BI__builtin_neon_vmlaltq_laneq_f16_mf8_fpm:
7106 return EmitFP8NeonFMLACall(IID: Intrinsic::aarch64_neon_fp8_fmlalt_lane,
7107 ExtendLaneArg, RetTy: HalfTy, Ops, E, name: "vmlal_lane");
7108 case NEON::BI__builtin_neon_vmlallbbq_lane_f32_mf8_fpm:
7109 ExtendLaneArg = true;
7110 [[fallthrough]];
7111 case NEON::BI__builtin_neon_vmlallbbq_laneq_f32_mf8_fpm:
7112 return EmitFP8NeonFMLACall(IID: Intrinsic::aarch64_neon_fp8_fmlallbb_lane,
7113 ExtendLaneArg, RetTy: FloatTy, Ops, E, name: "vmlall_lane");
7114 case NEON::BI__builtin_neon_vmlallbtq_lane_f32_mf8_fpm:
7115 ExtendLaneArg = true;
7116 [[fallthrough]];
7117 case NEON::BI__builtin_neon_vmlallbtq_laneq_f32_mf8_fpm:
7118 return EmitFP8NeonFMLACall(IID: Intrinsic::aarch64_neon_fp8_fmlallbt_lane,
7119 ExtendLaneArg, RetTy: FloatTy, Ops, E, name: "vmlall_lane");
7120 case NEON::BI__builtin_neon_vmlalltbq_lane_f32_mf8_fpm:
7121 ExtendLaneArg = true;
7122 [[fallthrough]];
7123 case NEON::BI__builtin_neon_vmlalltbq_laneq_f32_mf8_fpm:
7124 return EmitFP8NeonFMLACall(IID: Intrinsic::aarch64_neon_fp8_fmlalltb_lane,
7125 ExtendLaneArg, RetTy: FloatTy, Ops, E, name: "vmlall_lane");
7126 case NEON::BI__builtin_neon_vmlallttq_lane_f32_mf8_fpm:
7127 ExtendLaneArg = true;
7128 [[fallthrough]];
7129 case NEON::BI__builtin_neon_vmlallttq_laneq_f32_mf8_fpm:
7130 return EmitFP8NeonFMLACall(IID: Intrinsic::aarch64_neon_fp8_fmlalltt_lane,
7131 ExtendLaneArg, RetTy: FloatTy, Ops, E, name: "vmlall_lane");
7132 case NEON::BI__builtin_neon_vamin_f16:
7133 case NEON::BI__builtin_neon_vaminq_f16:
7134 case NEON::BI__builtin_neon_vamin_f32:
7135 case NEON::BI__builtin_neon_vaminq_f32:
7136 case NEON::BI__builtin_neon_vaminq_f64: {
7137 Int = Intrinsic::aarch64_neon_famin;
7138 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "famin");
7139 }
7140 case NEON::BI__builtin_neon_vamax_f16:
7141 case NEON::BI__builtin_neon_vamaxq_f16:
7142 case NEON::BI__builtin_neon_vamax_f32:
7143 case NEON::BI__builtin_neon_vamaxq_f32:
7144 case NEON::BI__builtin_neon_vamaxq_f64: {
7145 Int = Intrinsic::aarch64_neon_famax;
7146 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "famax");
7147 }
7148 case NEON::BI__builtin_neon_vscale_f16:
7149 case NEON::BI__builtin_neon_vscaleq_f16:
7150 case NEON::BI__builtin_neon_vscale_f32:
7151 case NEON::BI__builtin_neon_vscaleq_f32:
7152 case NEON::BI__builtin_neon_vscaleq_f64: {
7153 Int = Intrinsic::aarch64_neon_fp8_fscale;
7154 return EmitNeonCall(F: CGM.getIntrinsic(IID: Int, Tys: Ty), Ops, name: "fscale");
7155 }
7156 }
7157}
7158
7159Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID,
7160 const CallExpr *E) {
7161 assert((BuiltinID == BPF::BI__builtin_preserve_field_info ||
7162 BuiltinID == BPF::BI__builtin_btf_type_id ||
7163 BuiltinID == BPF::BI__builtin_preserve_type_info ||
7164 BuiltinID == BPF::BI__builtin_preserve_enum_value) &&
7165 "unexpected BPF builtin");
7166
7167 // A sequence number, injected into IR builtin functions, to
7168 // prevent CSE given the only difference of the function
7169 // may just be the debuginfo metadata.
7170 static uint32_t BuiltinSeqNum;
7171
7172 switch (BuiltinID) {
7173 default:
7174 llvm_unreachable("Unexpected BPF builtin");
7175 case BPF::BI__builtin_preserve_field_info: {
7176 const Expr *Arg = E->getArg(Arg: 0);
7177 bool IsBitField = Arg->IgnoreParens()->getObjectKind() == OK_BitField;
7178
7179 if (!getDebugInfo()) {
7180 CGM.Error(loc: E->getExprLoc(),
7181 error: "using __builtin_preserve_field_info() without -g");
7182 return IsBitField ? EmitLValue(E: Arg).getRawBitFieldPointer(CGF&: *this)
7183 : EmitLValue(E: Arg).emitRawPointer(CGF&: *this);
7184 }
7185
7186 // Enable underlying preserve_*_access_index() generation.
7187 bool OldIsInPreservedAIRegion = IsInPreservedAIRegion;
7188 IsInPreservedAIRegion = true;
7189 Value *FieldAddr = IsBitField ? EmitLValue(E: Arg).getRawBitFieldPointer(CGF&: *this)
7190 : EmitLValue(E: Arg).emitRawPointer(CGF&: *this);
7191 IsInPreservedAIRegion = OldIsInPreservedAIRegion;
7192
7193 ConstantInt *C = cast<ConstantInt>(Val: EmitScalarExpr(E: E->getArg(Arg: 1)));
7194 Value *InfoKind = ConstantInt::get(Ty: Int64Ty, V: C->getSExtValue());
7195
7196 // Built the IR for the preserve_field_info intrinsic.
7197 llvm::Function *FnGetFieldInfo = Intrinsic::getOrInsertDeclaration(
7198 M: &CGM.getModule(), id: Intrinsic::bpf_preserve_field_info,
7199 OverloadTys: {FieldAddr->getType()});
7200 return Builder.CreateCall(Callee: FnGetFieldInfo, Args: {FieldAddr, InfoKind});
7201 }
7202 case BPF::BI__builtin_btf_type_id:
7203 case BPF::BI__builtin_preserve_type_info: {
7204 if (!getDebugInfo()) {
7205 CGM.Error(loc: E->getExprLoc(), error: "using builtin function without -g");
7206 return nullptr;
7207 }
7208
7209 const Expr *Arg0 = E->getArg(Arg: 0);
7210 llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateStandaloneType(
7211 Ty: Arg0->getType(), Loc: Arg0->getExprLoc());
7212
7213 ConstantInt *Flag = cast<ConstantInt>(Val: EmitScalarExpr(E: E->getArg(Arg: 1)));
7214 Value *FlagValue = ConstantInt::get(Ty: Int64Ty, V: Flag->getSExtValue());
7215 Value *SeqNumVal = ConstantInt::get(Ty: Int32Ty, V: BuiltinSeqNum++);
7216
7217 llvm::Function *FnDecl;
7218 if (BuiltinID == BPF::BI__builtin_btf_type_id)
7219 FnDecl = Intrinsic::getOrInsertDeclaration(
7220 M: &CGM.getModule(), id: Intrinsic::bpf_btf_type_id, OverloadTys: {});
7221 else
7222 FnDecl = Intrinsic::getOrInsertDeclaration(
7223 M: &CGM.getModule(), id: Intrinsic::bpf_preserve_type_info, OverloadTys: {});
7224 CallInst *Fn = Builder.CreateCall(Callee: FnDecl, Args: {SeqNumVal, FlagValue});
7225 Fn->setMetadata(KindID: LLVMContext::MD_preserve_access_index, Node: DbgInfo);
7226 return Fn;
7227 }
7228 case BPF::BI__builtin_preserve_enum_value: {
7229 if (!getDebugInfo()) {
7230 CGM.Error(loc: E->getExprLoc(), error: "using builtin function without -g");
7231 return nullptr;
7232 }
7233
7234 const Expr *Arg0 = E->getArg(Arg: 0);
7235 llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateStandaloneType(
7236 Ty: Arg0->getType(), Loc: Arg0->getExprLoc());
7237
7238 // Find enumerator
7239 const auto *UO = cast<UnaryOperator>(Val: Arg0->IgnoreParens());
7240 const auto *CE = cast<CStyleCastExpr>(Val: UO->getSubExpr());
7241 const auto *DR = cast<DeclRefExpr>(Val: CE->getSubExpr());
7242 const auto *Enumerator = cast<EnumConstantDecl>(Val: DR->getDecl());
7243
7244 auto InitVal = Enumerator->getInitVal();
7245 std::string InitValStr;
7246 if (InitVal.isNegative() || InitVal > uint64_t(INT64_MAX))
7247 InitValStr = std::to_string(val: InitVal.getSExtValue());
7248 else
7249 InitValStr = std::to_string(val: InitVal.getZExtValue());
7250 std::string EnumStr = Enumerator->getNameAsString() + ":" + InitValStr;
7251 Value *EnumStrVal = Builder.CreateGlobalString(Str: EnumStr);
7252
7253 ConstantInt *Flag = cast<ConstantInt>(Val: EmitScalarExpr(E: E->getArg(Arg: 1)));
7254 Value *FlagValue = ConstantInt::get(Ty: Int64Ty, V: Flag->getSExtValue());
7255 Value *SeqNumVal = ConstantInt::get(Ty: Int32Ty, V: BuiltinSeqNum++);
7256
7257 llvm::Function *IntrinsicFn = Intrinsic::getOrInsertDeclaration(
7258 M: &CGM.getModule(), id: Intrinsic::bpf_preserve_enum_value, OverloadTys: {});
7259 CallInst *Fn =
7260 Builder.CreateCall(Callee: IntrinsicFn, Args: {SeqNumVal, EnumStrVal, FlagValue});
7261 Fn->setMetadata(KindID: LLVMContext::MD_preserve_access_index, Node: DbgInfo);
7262 return Fn;
7263 }
7264 }
7265}
7266
7267llvm::Value *CodeGenFunction::
7268BuildVector(ArrayRef<llvm::Value*> Ops) {
7269 assert((Ops.size() & (Ops.size() - 1)) == 0 &&
7270 "Not a power-of-two sized vector!");
7271 bool AllConstants = true;
7272 for (unsigned i = 0, e = Ops.size(); i != e && AllConstants; ++i)
7273 AllConstants &= isa<Constant>(Val: Ops[i]);
7274
7275 // If this is a constant vector, create a ConstantVector.
7276 if (AllConstants) {
7277 SmallVector<llvm::Constant*, 16> CstOps;
7278 for (llvm::Value *Op : Ops)
7279 CstOps.push_back(Elt: cast<Constant>(Val: Op));
7280 return llvm::ConstantVector::get(V: CstOps);
7281 }
7282
7283 // Otherwise, insertelement the values to build the vector.
7284 Value *Result = llvm::PoisonValue::get(
7285 T: llvm::FixedVectorType::get(ElementType: Ops[0]->getType(), NumElts: Ops.size()));
7286
7287 for (unsigned i = 0, e = Ops.size(); i != e; ++i)
7288 Result = Builder.CreateInsertElement(Vec: Result, NewElt: Ops[i], Idx: Builder.getInt64(C: i));
7289
7290 return Result;
7291}
7292
7293Value *CodeGenFunction::EmitAArch64CpuInit() {
7294 llvm::FunctionType *FTy = llvm::FunctionType::get(Result: VoidTy, isVarArg: false);
7295 llvm::FunctionCallee Func =
7296 CGM.CreateRuntimeFunction(Ty: FTy, Name: "__init_cpu_features_resolver");
7297 cast<llvm::GlobalValue>(Val: Func.getCallee())->setDSOLocal(true);
7298 cast<llvm::GlobalValue>(Val: Func.getCallee())
7299 ->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
7300 return Builder.CreateCall(Callee: Func);
7301}
7302
7303Value *CodeGenFunction::EmitAArch64CpuSupports(const CallExpr *E) {
7304 const Expr *ArgExpr = E->getArg(Arg: 0)->IgnoreParenCasts();
7305 StringRef ArgStr = cast<StringLiteral>(Val: ArgExpr)->getString();
7306 llvm::SmallVector<StringRef, 8> OrigFeatures;
7307 ArgStr.split(A&: OrigFeatures, Separator: "+");
7308 llvm::SmallVector<StringRef, 8> Features;
7309 for (StringRef Feature : OrigFeatures) {
7310 Feature = Feature.trim();
7311 if (!llvm::AArch64::parseFMVExtension(Extension: Feature))
7312 return Builder.getFalse();
7313 if (Feature != "default")
7314 Features.push_back(Elt: Feature);
7315 }
7316 return EmitAArch64CpuSupports(FeatureStrs: Features);
7317}
7318
7319llvm::Value *
7320CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
7321 llvm::APInt FeaturesMask = llvm::AArch64::getCpuSupportsMask(Features: FeaturesStrs);
7322 Value *Result = Builder.getTrue();
7323 if (FeaturesMask != 0) {
7324 // Get features from structure in runtime library
7325 // struct {
7326 // unsigned long long features;
7327 // } __aarch64_cpu_features;
7328 llvm::Type *STy = llvm::StructType::get(elt1: Int64Ty);
7329 llvm::Constant *AArch64CPUFeatures =
7330 CGM.CreateRuntimeVariable(Ty: STy, Name: "__aarch64_cpu_features");
7331 cast<llvm::GlobalValue>(Val: AArch64CPUFeatures)->setDSOLocal(true);
7332 llvm::Value *CpuFeatures = Builder.CreateGEP(
7333 Ty: STy, Ptr: AArch64CPUFeatures,
7334 IdxList: {ConstantInt::get(Ty: Int32Ty, V: 0), ConstantInt::get(Ty: Int32Ty, V: 0)});
7335 Value *Features = Builder.CreateAlignedLoad(Ty: Int64Ty, Addr: CpuFeatures,
7336 Align: CharUnits::fromQuantity(Quantity: 8));
7337 Value *Mask = Builder.getInt(AI: FeaturesMask.trunc(width: 64));
7338 Value *Bitset = Builder.CreateAnd(LHS: Features, RHS: Mask);
7339 Value *Cmp = Builder.CreateICmpEQ(LHS: Bitset, RHS: Mask);
7340 Result = Builder.CreateAnd(LHS: Result, RHS: Cmp);
7341 }
7342 return Result;
7343}
7344