clang 24.0.0git
CIRGenBuiltinX86.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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 x86/x86_64 Builtin calls as CIR or a function
10// call to be later resolved.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CIRGenBuilder.h"
15#include "CIRGenFunction.h"
16#include "CIRGenModule.h"
17#include "mlir/IR/Attributes.h"
18#include "mlir/IR/BuiltinAttributes.h"
19#include "mlir/IR/Location.h"
20#include "mlir/IR/Types.h"
21#include "mlir/IR/ValueRange.h"
27#include "llvm/ADT/Sequence.h"
28#include "llvm/Support/ErrorHandling.h"
29#include "llvm/TargetParser/X86TargetParser.h"
30#include <string>
31
32using namespace clang;
33using namespace clang::CIRGen;
34
35// OG has unordered comparison as a form of optimization in addition to
36// ordered comparison, while CIR doesn't.
37//
38// This means that we can't encode the comparison code of UGT (unordered
39// greater than), at least not at the CIR level.
40//
41// The boolean shouldInvert compensates for this.
42// For example: to get to the comparison code UGT, we pass in
43// emitVectorFCmp (OLE, shouldInvert = true) since OLE is the inverse of UGT.
44
45// There are several ways to support this otherwise:
46// - register extra CmpOpKind for unordered comparison types and build the
47// translation code for
48// to go from CIR -> LLVM dialect. Notice we get this naturally with
49// shouldInvert, benefiting from existing infrastructure, albeit having to
50// generate an extra `not` at CIR).
51// - Just add extra comparison code to a new VecCmpOpKind instead of
52// cluttering CmpOpKind.
53// - Add a boolean in VecCmpOp to indicate if it's doing unordered or ordered
54// comparison
55// - Just emit the intrinsics call instead of calling this helper, see how the
56// LLVM lowering handles this.
57static mlir::Value emitVectorFCmp(CIRGenFunction &cgf, const CallExpr &expr,
59 cir::CmpOpKind pred, bool shouldInvert) {
62 mlir::Value cmp = builder.createVecCompare(cgf.getLoc(expr.getExprLoc()),
63 pred, ops[0], ops[1]);
64 // TODO(cir): Add dedicated predicates to avoid the need to invert this.
65 mlir::Value bitCast = builder.createBitcast(
66 shouldInvert ? builder.createNot(cmp) : cmp, ops[0].getType());
67 return bitCast;
68}
69
70static mlir::Value getMaskVecValue(CIRGenBuilderTy &builder, mlir::Location loc,
71 mlir::Value mask, unsigned numElems) {
72 auto maskTy = cir::VectorType::get(
73 builder.getSIntNTy(1), cast<cir::IntType>(mask.getType()).getWidth());
74 mlir::Value maskVec = builder.createBitcast(mask, maskTy);
75
76 // If we have less than 8 elements, then the starting mask was an i8 and
77 // we need to extract down to the right number of elements.
78 if (numElems < 8) {
80 mlir::Type i32Ty = builder.getSInt32Ty();
81 for (auto i : llvm::seq<unsigned>(0, numElems))
82 indices.push_back(cir::IntAttr::get(i32Ty, i));
83
84 maskVec = builder.createVecShuffle(loc, maskVec, maskVec, indices);
85 }
86 return maskVec;
87}
88
89static mlir::Value emitX86Round(CIRGenFunction &cgf, unsigned builtinID,
90 const CallExpr *expr,
92 bool isScalar = builtinID == X86::BI__builtin_ia32_roundss ||
93 builtinID == X86::BI__builtin_ia32_roundsd;
94
95 unsigned roundingControl =
96 cgf.getZExtIntValueFromConstOp(isScalar ? ops[2] : ops[1]);
97
98 constexpr unsigned mxcsrMask = 0b100;
99 constexpr unsigned fRoundNoExcMask = 0b1000;
100 unsigned useMXCSR = mxcsrMask & roundingControl;
101 unsigned fRoundNoExc = fRoundNoExcMask & roundingControl;
102
103 CIRGenBuilderTy &builder = cgf.getBuilder();
104 mlir::Location loc = cgf.getLoc(expr->getExprLoc());
105
106 if (useMXCSR || !fRoundNoExc) {
107 StringRef intrinsicName;
108 switch (builtinID) {
109 default:
110 llvm_unreachable("Unexpected builtin");
111 case X86::BI__builtin_ia32_roundps:
112 intrinsicName = "x86.sse41.round.ps";
113 break;
114 case X86::BI__builtin_ia32_roundpd:
115 intrinsicName = "x86.sse41.round.pd";
116 break;
117 case X86::BI__builtin_ia32_roundps256:
118 intrinsicName = "x86.avx.round.ps.256";
119 break;
120 case X86::BI__builtin_ia32_roundpd256:
121 intrinsicName = "x86.avx.round.pd.256";
122 break;
123 case X86::BI__builtin_ia32_roundss:
124 intrinsicName = "x86.sse41.round.ss";
125 break;
126 case X86::BI__builtin_ia32_roundsd:
127 intrinsicName = "x86.sse41.round.sd";
128 break;
129 }
130
131 mlir::Type resTy = ops[0].getType();
132 return builder.emitIntrinsicCallOp(loc, intrinsicName, resTy, ops);
133 }
134
135 auto emitRoundOp = [&](mlir::Value x) -> mlir::Value {
136 constexpr unsigned roundingMask = 0b11;
137 unsigned roundingMode = roundingControl & roundingMask;
138
139 if (builder.getIsFPConstrained()) {
141
143 cir::FenvAttr fenv = builder.getConstrainedFPAttr();
144
145 switch (roundingMode) {
146 default:
147 llvm_unreachable("Invalid rounding mode");
148 case 0b00:
149 return cir::RoundEvenOp::create(builder, loc, x, fenv);
150 case 0b01:
151 return cir::FloorOp::create(builder, loc, x, fenv);
152 case 0b10:
153 return cir::CeilOp::create(builder, loc, x, fenv);
154 case 0b11:
155 return cir::TruncOp::create(builder, loc, x, fenv);
156 }
157 }
158
159 switch (roundingMode) {
160 default:
161 llvm_unreachable("Invalid rounding mode");
162 case 0b00:
163 return cir::RoundEvenOp::create(builder, loc, x);
164 case 0b01:
165 return cir::FloorOp::create(builder, loc, x);
166 case 0b10:
167 return cir::CeilOp::create(builder, loc, x);
168 case 0b11:
169 return cir::TruncOp::create(builder, loc, x);
170 }
171 };
172
173 if (isScalar) {
174 mlir::Value valAt0 = builder.createExtractElement(loc, ops[1], 0);
175 mlir::Value roundedAt0 = emitRoundOp(valAt0);
176 return builder.createInsertElement(loc, ops[0], roundedAt0, 0);
177 }
178
179 return emitRoundOp(ops[0]);
180}
181
182static mlir::Value emitX86CompressStore(CIRGenBuilderTy &builder,
183 mlir::Location loc,
185 auto resultTy = cast<cir::VectorType>(ops[1].getType());
186 mlir::Value maskValue =
187 getMaskVecValue(builder, loc, ops[2], resultTy.getSize());
188
189 return builder.emitIntrinsicCallOp(
190 loc, "masked.compressstore", cir::VoidType::get(builder.getContext()),
191 mlir::ValueRange{ops[1], ops[0], maskValue});
192}
193
194// Builds the VecShuffleOp for pshuflw and pshufhw x86 builtins.
195//
196// The vector is split into lanes of 8 word elements (16 bits). The lower or
197// upper half of each lane, controlled by `isLow`, is shuffled in the following
198// way: The immediate is truncated to 8 bits, separated into 4 2-bit fields. The
199// i-th field's value represents the resulting index of the i-th element in the
200// half lane after shuffling. The other half of the lane remains unchanged.
201static cir::VecShuffleOp emitPshufWord(CIRGenBuilderTy &builder,
202 const mlir::Value vec,
203 const mlir::Value immediate,
204 const mlir::Location loc,
205 const bool isLow) {
207
208 auto vecTy = cast<cir::VectorType>(vec.getType());
209 unsigned numElts = vecTy.getSize();
210
211 unsigned firstHalfStart = isLow ? 0 : 4;
212 unsigned secondHalfStart = 4 - firstHalfStart;
213
214 // Splat the 8-bits of immediate 4 times to help the loop wrap around.
215 imm = (imm & 0xff) * 0x01010101;
216
217 int64_t indices[32];
218 for (unsigned l = 0; l != numElts; l += 8) {
219 for (unsigned i = firstHalfStart; i != firstHalfStart + 4; ++i) {
220 indices[l + i] = l + (imm & 3) + firstHalfStart;
221 imm >>= 2;
222 }
223 for (unsigned i = secondHalfStart; i != secondHalfStart + 4; ++i)
224 indices[l + i] = l + i;
225 }
226
227 return builder.createVecShuffle(loc, vec, ArrayRef(indices, numElts));
228}
229
230// Builds the shuffle mask for pshufd and shufpd/shufps x86 builtins.
231// The shuffle mask is written to outIndices.
232static void
233computeFullLaneShuffleMask(CIRGenFunction &cgf, const mlir::Value vec,
234 uint32_t imm, const bool isShufP,
235 llvm::SmallVectorImpl<int64_t> &outIndices) {
236 auto vecTy = cast<cir::VectorType>(vec.getType());
237 unsigned numElts = vecTy.getSize();
238 unsigned numLanes = cgf.cgm.getDataLayout().getTypeSizeInBits(vecTy) / 128;
239 unsigned numLaneElts = numElts / numLanes;
240
241 // Splat the 8-bits of immediate 4 times to help the loop wrap around.
242 imm = (imm & 0xff) * 0x01010101;
243
244 for (unsigned l = 0; l != numElts; l += numLaneElts) {
245 for (unsigned i = 0; i != numLaneElts; ++i) {
246 uint32_t idx = imm % numLaneElts;
247 imm /= numLaneElts;
248 if (isShufP && i >= (numLaneElts / 2))
249 idx += numElts;
250 outIndices[l + i] = l + idx;
251 }
252 }
253
254 outIndices.resize(numElts);
255}
256
257static mlir::Value emitPrefetch(CIRGenFunction &cgf, unsigned builtinID,
258 const CallExpr *e,
259 const SmallVector<mlir::Value> &ops) {
260 CIRGenBuilderTy &builder = cgf.getBuilder();
261 mlir::Location location = cgf.getLoc(e->getExprLoc());
262 mlir::Type voidTy = builder.getVoidTy();
263 mlir::Value address = builder.createPtrBitcast(ops[0], voidTy);
264 bool isWrite{};
265 int locality{};
266
267 assert(builtinID == X86::BI_mm_prefetch || builtinID == X86::BI_m_prefetchw ||
268 builtinID == X86::BI_m_prefetch && "Expected prefetch builtin");
269
270 if (builtinID == X86::BI_mm_prefetch) {
271 int hint = cgf.getSExtIntValueFromConstOp(ops[1]);
272 isWrite = (hint >> 2) & 0x1;
273 locality = hint & 0x3;
274 } else {
275 isWrite = (builtinID == X86::BI_m_prefetchw);
276 locality = 0x3;
277 }
278
279 cir::PrefetchOp::create(builder, location, address, locality, isWrite);
280 return {};
281}
282
283static mlir::Value emitX86CompressExpand(CIRGenBuilderTy &builder,
284 mlir::Location loc, mlir::Value source,
285 mlir::Value mask,
286 mlir::Value inputVector,
287 const std::string &id) {
288 auto resultTy = cast<cir::VectorType>(mask.getType());
289 mlir::Value maskValue = getMaskVecValue(
290 builder, loc, inputVector, cast<cir::VectorType>(resultTy).getSize());
291 return builder.emitIntrinsicCallOp(loc, id, resultTy,
292 mlir::ValueRange{source, mask, maskValue});
293}
294
295static mlir::Value
296emitEncodeKey(mlir::MLIRContext *context, CIRGenBuilderTy &builder,
297 const mlir::Location &location, mlir::ValueRange inputOperands,
298 mlir::Value outputOperand, std::uint8_t vecOutputCount,
299 const std::string &intrinsicName, std::uint8_t numResults) {
300 cir::VectorType resVector = cir::VectorType::get(builder.getUInt64Ty(), 2);
302 llvm::append_range(members,
303 llvm::SmallVector<mlir::Type>(vecOutputCount, resVector));
304 cir::StructType resRecord = cir::StructType::get(
305 context, members, /*packed=*/false,
306 /*is_class=*/false, cir::RecordType::getAllDataKinds(members));
307
308 mlir::Value outputPtr =
309 builder.createBitcast(outputOperand, cir::PointerType::get(resVector));
310 mlir::Value call = builder.emitIntrinsicCallOp(location, intrinsicName,
311 resRecord, inputOperands);
312 for (std::uint8_t i = 0; i < numResults; ++i) {
313 mlir::Value vecValue =
314 cir::ExtractMemberOp::create(builder, location, call, i + 1);
315 mlir::Value index = builder.getSInt32(i, location);
316 mlir::Value ptr = builder.createPtrStride(location, outputPtr, index);
317 builder.createStore(location, vecValue, Address{ptr, CharUnits::One()});
318 }
319 return cir::ExtractMemberOp::create(builder, location, call, 0);
320}
321
322static mlir::Value emitX86Select(CIRGenBuilderTy &builder, mlir::Location loc,
323 mlir::Value mask, mlir::Value op0,
324 mlir::Value op1) {
325 auto constOp = mlir::dyn_cast_or_null<cir::ConstantOp>(mask.getDefiningOp());
326 // If the mask is all ones just return first argument.
327 if (constOp && constOp.isAllOnesValue())
328 return op0;
329
330 mask = getMaskVecValue(builder, loc, mask,
331 cast<cir::VectorType>(op0.getType()).getSize());
332
333 return cir::VecTernaryOp::create(builder, loc, mask, op0, op1);
334}
335
336// Helper function to extract zero-bit from a mask as a boolean
337static mlir::Value getMaskZeroBitAsBool(CIRGenBuilderTy &builder,
338 mlir::Location loc, mlir::Value mask) {
339 // Get the mask as a vector of i1 and extract bit 0
340 auto intTy = mlir::dyn_cast<cir::IntType>(mask.getType());
341 assert(intTy && "mask must be an integer type");
342 unsigned width = intTy.getWidth();
343
344 auto maskVecTy = cir::VectorType::get(builder.getSIntNTy(1), width);
345 mlir::Value maskVec = builder.createBitcast(mask, maskVecTy);
346
347 // Extract bit 0 from the mask vector
348 mlir::Value bit0 = builder.createExtractElement(loc, maskVec, uint64_t(0));
349
350 // Convert i1 to bool for select
351 auto boolTy = cir::BoolType::get(builder.getContext());
352 return cir::CastOp::create(builder, loc, boolTy, cir::CastKind::int_to_bool,
353 bit0);
354}
355
356static mlir::Value emitX86ScalarSelect(CIRGenBuilderTy &builder,
357 mlir::Location loc, mlir::Value mask,
358 mlir::Value op0, mlir::Value op1) {
359
360 // If the mask is all ones just return first argument.
361 if (auto c = mlir::dyn_cast_or_null<cir::ConstantOp>(mask.getDefiningOp()))
362 if (c.isAllOnesValue())
363 return op0;
364
365 mlir::Value cond = getMaskZeroBitAsBool(builder, loc, mask);
366 return builder.createSelect(loc, cond, op0, op1);
367}
368
369static mlir::Value emitX86MaskAddLogic(CIRGenBuilderTy &builder,
370 mlir::Location loc,
371 const std::string &intrinsicName,
373
374 auto intTy = cast<cir::IntType>(ops[0].getType());
375 unsigned numElts = intTy.getWidth();
376 mlir::Value lhsVec = getMaskVecValue(builder, loc, ops[0], numElts);
377 mlir::Value rhsVec = getMaskVecValue(builder, loc, ops[1], numElts);
378 mlir::Type vecTy = lhsVec.getType();
379 mlir::Value resVec = builder.emitIntrinsicCallOp(
380 loc, intrinsicName, vecTy, mlir::ValueRange{lhsVec, rhsVec});
381 return builder.createBitcast(resVec, ops[0].getType());
382}
383
384static mlir::Value emitX86MaskUnpack(CIRGenBuilderTy &builder,
385 mlir::Location loc,
386 const std::string &intrinsicName,
388 unsigned numElems = cast<cir::IntType>(ops[0].getType()).getWidth();
389
390 // Convert both operands to mask vectors.
391 mlir::Value lhs = getMaskVecValue(builder, loc, ops[0], numElems);
392 mlir::Value rhs = getMaskVecValue(builder, loc, ops[1], numElems);
393
394 mlir::Type i32Ty = builder.getSInt32Ty();
395
396 // Create indices for extracting the first half of each vector.
398 for (auto i : llvm::seq<unsigned>(0, numElems / 2))
399 halfIndices.push_back(cir::IntAttr::get(i32Ty, i));
400
401 // Extract first half of each vector. This gives better codegen than
402 // doing it in a single shuffle.
403 mlir::Value lhsHalf = builder.createVecShuffle(loc, lhs, lhs, halfIndices);
404 mlir::Value rhsHalf = builder.createVecShuffle(loc, rhs, rhs, halfIndices);
405
406 // Create indices for concatenating the vectors.
407 // NOTE: Operands are swapped to match the intrinsic definition.
408 // After the half extraction, both vectors have numElems/2 elements.
409 // In createVecShuffle(rhsHalf, lhsHalf, indices), indices [0..numElems/2-1]
410 // select from rhsHalf, and indices [numElems/2..numElems-1] select from
411 // lhsHalf.
413 for (auto i : llvm::seq<unsigned>(0, numElems))
414 concatIndices.push_back(cir::IntAttr::get(i32Ty, i));
415
416 // Concat the vectors (RHS first, then LHS).
417 mlir::Value res =
418 builder.createVecShuffle(loc, rhsHalf, lhsHalf, concatIndices);
419 return builder.createBitcast(res, ops[0].getType());
420}
421
422template <typename BinOp>
423static mlir::Value
424emitX86MaskLogic(CIRGenBuilderTy &builder, mlir::Location loc,
425 SmallVectorImpl<mlir::Value> &ops, bool invertLHS = false) {
426 unsigned numElts = cast<cir::IntType>(ops[0].getType()).getWidth();
427 mlir::Value lhs = getMaskVecValue(builder, loc, ops[0], numElts);
428 mlir::Value rhs = getMaskVecValue(builder, loc, ops[1], numElts);
429
430 if (invertLHS)
431 lhs = builder.createNot(lhs);
432 return builder.createBitcast(BinOp::create(builder, loc, lhs, rhs),
433 ops[0].getType());
434}
435
436static mlir::Value emitX86MaskTest(CIRGenBuilderTy &builder, mlir::Location loc,
437 const std::string &intrinsicName,
439 auto intTy = cast<cir::IntType>(ops[0].getType());
440 unsigned numElts = intTy.getWidth();
441 mlir::Value lhsVec = getMaskVecValue(builder, loc, ops[0], numElts);
442 mlir::Value rhsVec = getMaskVecValue(builder, loc, ops[1], numElts);
443 mlir::Type resTy = builder.getSInt32Ty();
444 return builder.emitIntrinsicCallOp(loc, intrinsicName, resTy,
445 mlir::ValueRange{lhsVec, rhsVec});
446}
447
448static mlir::Value emitX86MaskedCompareResult(CIRGenBuilderTy &builder,
449 mlir::Value cmp, unsigned numElts,
450 mlir::Value maskIn,
451 mlir::Location loc) {
452 if (maskIn) {
453 auto c = mlir::dyn_cast_or_null<cir::ConstantOp>(maskIn.getDefiningOp());
454 if (!c || !c.isAllOnesValue())
455 cmp = builder.createAnd(loc, cmp,
456 getMaskVecValue(builder, loc, maskIn, numElts));
457 }
458 if (numElts < 8) {
460 mlir::Type i64Ty = builder.getSInt64Ty();
461
462 for (unsigned i = 0; i != numElts; ++i)
463 indices.push_back(cir::IntAttr::get(i64Ty, i));
464 for (unsigned i = numElts; i != 8; ++i)
465 indices.push_back(cir::IntAttr::get(i64Ty, i % numElts + numElts));
466
467 // This should shuffle between cmp (first vector) and null (second vector)
468 mlir::Value nullVec = builder.getNullValue(cmp.getType(), loc);
469 cmp = builder.createVecShuffle(loc, cmp, nullVec, indices);
470 }
471 return builder.createBitcast(cmp, builder.getUIntNTy(std::max(numElts, 8U)));
472}
473
474// TODO: The cgf parameter should be removed when all the NYI cases are
475// implemented.
476static std::optional<mlir::Value>
477emitX86MaskedCompare(CIRGenBuilderTy &builder, unsigned cc, bool isSigned,
478 ArrayRef<mlir::Value> ops, mlir::Location loc) {
479 assert((ops.size() == 2 || ops.size() == 4) &&
480 "Unexpected number of arguments");
481 unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize();
482 mlir::Value cmp;
483 if (cc == 3) {
484 cmp = builder.getNullValue(
485 cir::VectorType::get(builder.getSIntNTy(1), numElts), loc);
486 } else if (cc == 7) {
487 cir::VectorType resultTy =
488 cir::VectorType::get(builder.getSIntNTy(1), numElts);
489 llvm::APInt allOnes = llvm::APInt::getAllOnes(1);
490 cmp = cir::VecSplatOp::create(
491 builder, loc, resultTy,
492 builder.getConstAPInt(loc, builder.getSIntNTy(1), allOnes));
493 } else {
494 cir::CmpOpKind pred;
495 switch (cc) {
496 default:
497 llvm_unreachable("Unknown condition code");
498 case 0:
499 pred = cir::CmpOpKind::eq;
500 break;
501 case 1:
502 pred = cir::CmpOpKind::lt;
503 break;
504 case 2:
505 pred = cir::CmpOpKind::le;
506 break;
507 case 4:
508 pred = cir::CmpOpKind::ne;
509 break;
510 case 5:
511 pred = cir::CmpOpKind::ge;
512 break;
513 case 6:
514 pred = cir::CmpOpKind::gt;
515 break;
516 }
517
518 auto resultTy = cir::VectorType::get(builder.getSIntNTy(1), numElts);
519 cmp = cir::VecCmpOp::create(builder, loc, resultTy, pred, ops[0], ops[1]);
520 }
521
522 mlir::Value maskIn;
523 if (ops.size() == 4)
524 maskIn = ops[3];
525
526 return emitX86MaskedCompareResult(builder, cmp, numElts, maskIn, loc);
527}
528
529// TODO: The cgf parameter should be removed when all the NYI cases are
530// implemented.
531static std::optional<mlir::Value> emitX86ConvertToMask(CIRGenFunction &cgf,
532 CIRGenBuilderTy &builder,
533 mlir::Value in,
534 mlir::Location loc) {
535 cir::ConstantOp zero = builder.getNullValue(in.getType(), loc);
536 return emitX86MaskedCompare(builder, 1, true, {in, zero}, loc);
537}
538
539static std::optional<mlir::Value> emitX86SExtMask(CIRGenBuilderTy &builder,
540 mlir::Value op,
541 mlir::Type dstTy,
542 mlir::Location loc) {
543 unsigned numberOfElements = cast<cir::VectorType>(dstTy).getSize();
544 mlir::Value mask = getMaskVecValue(builder, loc, op, numberOfElements);
545
546 return builder.createCast(loc, cir::CastKind::integral, mask, dstTy);
547}
548
549static mlir::Value emitVecInsert(CIRGenBuilderTy &builder, mlir::Location loc,
550 mlir::Value vec, mlir::Value value,
551 mlir::Value indexOp) {
552 unsigned numElts = cast<cir::VectorType>(vec.getType()).getSize();
553
554 uint64_t index =
555 indexOp.getDefiningOp<cir::ConstantOp>().getIntValue().getZExtValue();
556
557 index &= numElts - 1;
558
559 cir::ConstantOp indexVal = builder.getUInt64(index, loc);
560
561 return cir::VecInsertOp::create(builder, loc, vec, value, indexVal);
562}
563
564static mlir::Value emitX86FunnelShift(CIRGenBuilderTy &builder,
565 mlir::Location location, mlir::Value &op0,
566 mlir::Value &op1, mlir::Value &amt,
567 bool isRight) {
568 mlir::Type op0Ty = op0.getType();
569
570 // Amount may be scalar immediate, in which case create a splat vector.
571 // Funnel shifts amounts are treated as modulo and types are all power-of-2
572 // so we only care about the lowest log2 bits anyway.
573 if (amt.getType() != op0Ty) {
574 auto vecTy = mlir::cast<cir::VectorType>(op0Ty);
575 uint64_t numElems = vecTy.getSize();
576
577 auto amtTy = mlir::cast<cir::IntType>(amt.getType());
578 auto vecElemTy = mlir::cast<cir::IntType>(vecTy.getElementType());
579
580 // If signed, cast to the same width but unsigned first to
581 // ensure zero-extension when casting to a bigger unsigned `vecElemeTy`.
582 if (amtTy.isSigned()) {
583 cir::IntType unsignedAmtTy = builder.getUIntNTy(amtTy.getWidth());
584 amt = builder.createIntCast(amt, unsignedAmtTy);
585 }
586 cir::IntType unsignedVecElemType = builder.getUIntNTy(vecElemTy.getWidth());
587 amt = builder.createIntCast(amt, unsignedVecElemType);
588 amt = cir::VecSplatOp::create(
589 builder, location, cir::VectorType::get(unsignedVecElemType, numElems),
590 amt);
591 }
592
593 const StringRef intrinsicName = isRight ? "fshr" : "fshl";
594 return builder.emitIntrinsicCallOp(location, intrinsicName, op0Ty,
595 mlir::ValueRange{op0, op1, amt});
596}
597
598static mlir::Value emitX86Muldq(CIRGenBuilderTy &builder, mlir::Location loc,
599 bool isSigned,
601 unsigned opTypePrimitiveSizeInBits) {
602 mlir::Type ty = cir::VectorType::get(builder.getSInt64Ty(),
603 opTypePrimitiveSizeInBits / 64);
604 mlir::Value lhs = builder.createBitcast(loc, ops[0], ty);
605 mlir::Value rhs = builder.createBitcast(loc, ops[1], ty);
606 if (isSigned) {
607 cir::ConstantOp shiftAmt =
608 builder.getConstant(loc, cir::IntAttr::get(builder.getSInt64Ty(), 32));
609 cir::VecSplatOp shiftSplatVecOp =
610 cir::VecSplatOp::create(builder, loc, ty, shiftAmt.getResult());
611 mlir::Value shiftSplatValue = shiftSplatVecOp.getResult();
612 // In CIR, right-shift operations are automatically lowered to either an
613 // arithmetic or logical shift depending on the operand type. The purpose
614 // of the shifts here is to propagate the sign bit of the 32-bit input
615 // into the upper bits of each vector lane.
616 lhs = builder.createShift(loc, lhs, shiftSplatValue, true);
617 lhs = builder.createShift(loc, lhs, shiftSplatValue, false);
618 rhs = builder.createShift(loc, rhs, shiftSplatValue, true);
619 rhs = builder.createShift(loc, rhs, shiftSplatValue, false);
620 } else {
621 cir::ConstantOp maskScalar = builder.getConstant(
622 loc, cir::IntAttr::get(builder.getSInt64Ty(), 0xffffffff));
623 cir::VecSplatOp mask =
624 cir::VecSplatOp::create(builder, loc, ty, maskScalar.getResult());
625 // Clear the upper bits
626 lhs = builder.createAnd(loc, lhs, mask);
627 rhs = builder.createAnd(loc, rhs, mask);
628 }
629 return builder.createMul(loc, lhs, rhs);
630}
631
632// Convert f16 half values to floats.
633static mlir::Value emitX86CvtF16ToFloatExpr(CIRGenBuilderTy &builder,
634 mlir::Location loc,
636 mlir::Type dstTy) {
637 assert((ops.size() == 1 || ops.size() == 3 || ops.size() == 4) &&
638 "Unknown cvtph2ps intrinsic");
639
640 // If the SAE intrinsic doesn't use default rounding then we can't upgrade.
641 if (ops.size() == 4) {
642 auto constOp = ops[3].getDefiningOp<cir::ConstantOp>();
643 assert(constOp && "Expected constant operand");
644 if (constOp.getIntValue().getZExtValue() != 4) {
645 return builder.emitIntrinsicCallOp(loc, "x86.avx512.mask.vcvtph2ps.512",
646 dstTy, ops);
647 }
648 }
649
650 unsigned numElts = cast<cir::VectorType>(dstTy).getSize();
651 mlir::Value src = ops[0];
652
653 // Extract the subvector
654 if (numElts != cast<cir::VectorType>(src.getType()).getSize()) {
655 assert(numElts == 4 && "Unexpected vector size");
656 src = builder.createVecShuffle(loc, src, {0, 1, 2, 3});
657 }
658
659 // Bitcast from vXi16 to vXf16.
660 cir::VectorType halfTy =
661 cir::VectorType::get(cir::FP16Type::get(builder.getContext()), numElts);
662
663 src = builder.createCast(cir::CastKind::bitcast, src, halfTy);
664
665 // Perform the fp-extension
666 mlir::Value res = builder.createCast(cir::CastKind::floating, src, dstTy);
667
668 if (ops.size() >= 3)
669 res = emitX86Select(builder, loc, ops[2], res, ops[1]);
670 return res;
671}
672
673static mlir::Value emitX86vpcom(CIRGenBuilderTy &builder, mlir::Location loc,
675 bool isSigned) {
676 mlir::Value op0 = ops[0];
677 mlir::Value op1 = ops[1];
678
679 cir::VectorType ty = cast<cir::VectorType>(op0.getType());
680 cir::IntType elementTy = cast<cir::IntType>(ty.getElementType());
681
682 uint64_t imm = CIRGenFunction::getZExtIntValueFromConstOp(ops[2]) & 0x7;
683
684 cir::CmpOpKind pred;
685 switch (imm) {
686 case 0x0:
687 pred = cir::CmpOpKind::lt;
688 break;
689 case 0x1:
690 pred = cir::CmpOpKind::le;
691 break;
692 case 0x2:
693 pred = cir::CmpOpKind::gt;
694 break;
695 case 0x3:
696 pred = cir::CmpOpKind::ge;
697 break;
698 case 0x4:
699 pred = cir::CmpOpKind::eq;
700 break;
701 case 0x5:
702 pred = cir::CmpOpKind::ne;
703 break;
704 case 0x6:
705 return builder.getNullValue(ty, loc); // FALSE
706 case 0x7: {
707 llvm::APInt allOnes = llvm::APInt::getAllOnes(elementTy.getWidth());
708 return cir::VecSplatOp::create(
709 builder, loc, ty,
710 builder.getConstAPInt(loc, elementTy, allOnes)); // TRUE
711 }
712 default:
713 llvm_unreachable("Unexpected XOP vpcom/vpcomu predicate");
714 }
715
716 if ((!isSigned && elementTy.isSigned()) ||
717 (isSigned && elementTy.isUnsigned())) {
718 elementTy = elementTy.isSigned() ? builder.getUIntNTy(elementTy.getWidth())
719 : builder.getSIntNTy(elementTy.getWidth());
720 ty = cir::VectorType::get(elementTy, ty.getSize());
721 op0 = builder.createBitcast(op0, ty);
722 op1 = builder.createBitcast(op1, ty);
723 }
724
725 return builder.createVecCompare(loc, pred, op0, op1);
726}
727
728static mlir::Value emitX86Fpclass(CIRGenBuilderTy &builder, mlir::Location loc,
729 unsigned builtinID,
731 unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize();
732 mlir::Value maskIn = ops[2];
733 ops.erase(ops.begin() + 2);
734
735 StringRef intrinsicName;
736 switch (builtinID) {
737 default:
738 llvm_unreachable("Unsupported fpclass builtin");
739 case X86::BI__builtin_ia32_vfpclassbf16128_mask:
740 intrinsicName = "x86.avx10.fpclass.bf16.128";
741 break;
742 case X86::BI__builtin_ia32_vfpclassbf16256_mask:
743 intrinsicName = "x86.avx10.fpclass.bf16.256";
744 break;
745 case X86::BI__builtin_ia32_vfpclassbf16512_mask:
746 intrinsicName = "x86.avx10.fpclass.bf16.512";
747 break;
748 case X86::BI__builtin_ia32_fpclassph128_mask:
749 intrinsicName = "x86.avx512fp16.fpclass.ph.128";
750 break;
751 case X86::BI__builtin_ia32_fpclassph256_mask:
752 intrinsicName = "x86.avx512fp16.fpclass.ph.256";
753 break;
754 case X86::BI__builtin_ia32_fpclassph512_mask:
755 intrinsicName = "x86.avx512fp16.fpclass.ph.512";
756 break;
757 case X86::BI__builtin_ia32_fpclassps128_mask:
758 intrinsicName = "x86.avx512.fpclass.ps.128";
759 break;
760 case X86::BI__builtin_ia32_fpclassps256_mask:
761 intrinsicName = "x86.avx512.fpclass.ps.256";
762 break;
763 case X86::BI__builtin_ia32_fpclassps512_mask:
764 intrinsicName = "x86.avx512.fpclass.ps.512";
765 break;
766 case X86::BI__builtin_ia32_fpclasspd128_mask:
767 intrinsicName = "x86.avx512.fpclass.pd.128";
768 break;
769 case X86::BI__builtin_ia32_fpclasspd256_mask:
770 intrinsicName = "x86.avx512.fpclass.pd.256";
771 break;
772 case X86::BI__builtin_ia32_fpclasspd512_mask:
773 intrinsicName = "x86.avx512.fpclass.pd.512";
774 break;
775 }
776
777 auto cmpResultTy = cir::VectorType::get(builder.getSIntNTy(1), numElts);
778 mlir::Value fpclass =
779 builder.emitIntrinsicCallOp(loc, intrinsicName, cmpResultTy, ops);
780 return emitX86MaskedCompareResult(builder, fpclass, numElts, maskIn, loc);
781}
782
783static mlir::Value emitX86Aes(CIRGenBuilderTy &builder, mlir::Location loc,
784 llvm::StringRef intrinsicName, mlir::Type retType,
786 // Create return struct type and call intrinsic function.
787 mlir::Type vecType =
788 mlir::cast<cir::PointerType>(ops[0].getType()).getPointee();
789 mlir::Type rstMembers[] = {retType, vecType};
790 cir::RecordType rstRecTy =
791 builder.getAnonRecordTy(rstMembers, /*packed=*/false,
793 mlir::Value rstValueRec = builder.emitIntrinsicCallOp(
794 loc, intrinsicName, rstRecTy, mlir::ValueRange{ops[1], ops[2]});
795
796 // Extract the first return value and truncate it to 1 bit, then cast result
797 // to bool value.
798 mlir::Value flag =
799 cir::ExtractMemberOp::create(builder, loc, rstValueRec, /*index=*/0);
800 mlir::Value flagBit0 = builder.createCast(loc, cir::CastKind::integral, flag,
801 builder.getUIntNTy(1));
802 mlir::Value succ = builder.createCast(loc, cir::CastKind::int_to_bool,
803 flagBit0, builder.getBoolTy());
804
805 // Extract the second return value, store it to output address if success.
806 mlir::Value out =
807 cir::ExtractMemberOp::create(builder, loc, rstValueRec, /*index=*/1);
808 Address outAddr(ops[0], /*align=*/CharUnits::fromQuantity(16));
809 cir::IfOp::create(
810 builder, loc, succ, /*withElseRegion=*/true,
811 /*thenBuilder=*/
812 [&](mlir::OpBuilder &b, mlir::Location) {
813 builder.createStore(loc, out, outAddr);
814 builder.createYield(loc);
815 },
816 /*elseBuilder=*/
817 [&](mlir::OpBuilder &b, mlir::Location) {
818 mlir::Value zero = builder.getNullValue(vecType, loc);
819 builder.createStore(loc, zero, outAddr);
820 builder.createYield(loc);
821 });
822
823 return cir::ExtractMemberOp::create(builder, loc, rstValueRec, /*index=*/0);
824}
825
826static mlir::Value emitX86Aeswide(CIRGenBuilderTy &builder, mlir::Location loc,
827 llvm::StringRef intrinsicName,
828 mlir::Type retType,
830 mlir::Type vecType =
831 mlir::cast<cir::PointerType>(ops[1].getType()).getPointee();
832
833 // Create struct for return type and load input arguments, then call
834 // intrinsic function.
835 mlir::Type recTypes[9] = {retType, vecType, vecType, vecType, vecType,
836 vecType, vecType, vecType, vecType};
837 mlir::Value arguments[9];
838 arguments[0] = ops[2];
839 for (int i = 0; i < 8; i++) {
840 // Loading each vector argument from input address.
841 cir::ConstantOp idx = builder.getUInt32(i, loc);
842 mlir::Value nextInElePtr =
843 builder.getArrayElement(loc, loc, ops[1], vecType, idx,
844 /*shouldDecay=*/false);
845 arguments[i + 1] =
846 builder.createAlignedLoad(loc, vecType, nextInElePtr,
847 /*align=*/CharUnits::fromQuantity(16));
848 }
849 cir::RecordType rstRecTy = builder.getAnonRecordTy(
850 recTypes, /*packed=*/false, cir::RecordType::getAllDataKinds(recTypes));
851 mlir::Value rstValueRec =
852 builder.emitIntrinsicCallOp(loc, intrinsicName, rstRecTy, arguments);
853
854 // Extract the first return value and truncate it to 1 bit, then cast result
855 // to bool value.
856 mlir::Value flag =
857 cir::ExtractMemberOp::create(builder, loc, rstValueRec, /*index=*/0);
858 mlir::Value flagBit0 = builder.createCast(loc, cir::CastKind::integral, flag,
859 builder.getUIntNTy(1));
860 mlir::Value succ = builder.createCast(loc, cir::CastKind::int_to_bool,
861 flagBit0, builder.getBoolTy());
862
863 // Extract other return values, store those to output address if success.
864 cir::IfOp::create(
865 builder, loc, succ, /*withElseRegion=*/true,
866 /*thenBuilder=*/
867 [&](mlir::OpBuilder &b, mlir::Location) {
868 for (int i = 0; i < 8; i++) {
869 mlir::Value out =
870 cir::ExtractMemberOp::create(builder, loc, rstValueRec,
871 /*index=*/i + 1);
872 cir::ConstantOp idx = builder.getUInt32(i, loc);
873 mlir::Value nextOutEleAddr =
874 builder.getArrayElement(loc, loc, ops[0], vecType, idx,
875 /*shouldDecay=*/false);
876 Address outAddr(nextOutEleAddr,
877 /*align=*/CharUnits::fromQuantity(16));
878 builder.createStore(loc, out, outAddr);
879 }
880 builder.createYield(loc);
881 },
882 /*elseBuilder=*/
883 [&](mlir::OpBuilder &b, mlir::Location) {
884 mlir::Value zero = builder.getNullValue(vecType, loc);
885 for (int i = 0; i < 8; i++) {
886 cir::ConstantOp idx = builder.getUInt32(i, loc);
887 mlir::Value nextOutEleAddr =
888 builder.getArrayElement(loc, loc, ops[0], vecType, idx,
889 /*shouldDecay=*/false);
890 Address outAddr(nextOutEleAddr,
891 /*align=*/CharUnits::fromQuantity(16));
892 builder.createStore(loc, zero, outAddr);
893 }
894 builder.createYield(loc);
895 });
896
897 return cir::ExtractMemberOp::create(builder, loc, rstValueRec, /*index=*/0);
898}
899
900static mlir::Value emitX86MaskedLoad(CIRGenBuilderTy &builder,
902 llvm::Align alignment,
903 mlir::Location loc) {
904 mlir::Type ty = ops[1].getType();
905 mlir::Value ptr = ops[0];
906 mlir::Value maskVec = getMaskVecValue(builder, loc, ops[2],
907 cast<cir::VectorType>(ty).getSize());
908
909 return builder.createMaskedLoad(loc, ty, ptr, alignment, maskVec, ops[1]);
910}
911
912static mlir::Value emitX86VPerm2f128(CIRGenBuilderTy &builder,
913 mlir::Location loc,
915 auto inputType = cast<cir::VectorType>(ops[0].getType());
916 assert(!inputType.getIsScalable() &&
917 "This is only intended for fixed-width vectors");
918
920 mlir::Value zeroVec = builder.getZero(loc, inputType);
921
922 // If both lanes are zero, return a zero result.
923 if ((imm & 0x80) && (imm & 0x08))
924 return zeroVec;
925
926 mlir::Value lanes[2];
928
929 cir::IntType i32Ty = builder.getSInt32Ty();
930 const unsigned numElts = inputType.getSize();
931 // We must evaluated each lane(128 bits) separetely
932 for (auto lane : llvm::seq(0, 2)) {
933 bool isZeroBit = imm & (1 << ((lane * 4) + 3)),
934 isSourceB = imm & (1 << ((lane * 4) + 1)),
935 isUpperHalf = imm & (1 << (lane * 4));
936
937 // Determine the source for this lane
938 if (isZeroBit)
939 lanes[lane] = zeroVec;
940 else
941 lanes[lane] = isSourceB ? ops[1] : ops[0];
942
943 // We need to built the shuffle mask selecting the right half
944 for (auto elt : llvm::seq(0u, numElts / 2u)) {
945 unsigned idx = (lane * numElts) + elt;
946 if (isUpperHalf)
947 idx += numElts / 2;
948 mask.push_back(cir::IntAttr::get(i32Ty, idx));
949 }
950 }
951
952 return builder.createVecShuffle(loc, lanes[0], lanes[1], mask);
953}
954
955static mlir::Value emitX86PackedByteShift(CIRGenBuilderTy &builder,
956 unsigned builtinID,
957 mlir::Location loc,
959 llvm::Boolean isLeftShift) {
960 auto byteVecType = cast<cir::VectorType>(ops[0].getType());
961 assert(!byteVecType.getIsScalable() &&
962 "This is only intended for fixed-width vectors");
963
964 unsigned shiftVal = CIRGenFunction::getZExtIntValueFromConstOp(ops[1]) & 0xFF;
965 mlir::Value zeroVector = builder.getZero(loc, byteVecType);
966
967 // If pslldq is shifting the vector more than 15 bytes, emit zero.
968 // This matches the hardware behavior where shifting by 16+ bytes
969 // clears the entire 128-bit lane.
970 if (shiftVal >= 16)
971 return zeroVector;
972
973 uint64_t numElts = byteVecType.getSize();
974 assert(numElts % 16 == 0 && "Expected a multiple of 16");
975
977
978 constexpr unsigned laneSize = 16;
979 const int switchOperand = numElts - laneSize;
980
981 // 256/512-bit pslldq/psrldq operates on 128-bit lanes so we need to
982 // handle that
983 for (auto laneOffset = 0ull; laneOffset < numElts; laneOffset += laneSize) {
984 for (auto elt : llvm::seq<unsigned>(0, laneSize)) {
985 unsigned idx =
986 isLeftShift ? (numElts + elt - shiftVal) : (elt + shiftVal);
987
988 bool isZeroPadding = isLeftShift ? (idx < numElts) : (idx >= laneSize);
989 if (isZeroPadding)
990 idx += isLeftShift ? (-switchOperand) : switchOperand;
991
992 shuffleMask.push_back(idx + laneOffset);
993 }
994 }
995
996 // Perform the shuffle
997 // (left concatenating zeros on left, right concatenating zeros on right)
998 auto [firstOperand, secondOperand] = isLeftShift
999 ? std::make_pair(zeroVector, ops[0])
1000 : std::make_pair(ops[0], zeroVector);
1001
1002 // Mask the result using circular arithmetic on concatenated buffer
1003 mlir::Value shuffleResult =
1004 builder.createVecShuffle(loc, firstOperand, secondOperand, shuffleMask);
1005
1006 return shuffleResult;
1007}
1008
1010 const Expr *cpuExpr = expr->getArg(0)->IgnoreParenCasts();
1011 StringRef cpuStr = cast<clang::StringLiteral>(cpuExpr)->getString();
1012 return emitX86CpuIs(getLoc(expr->getExprLoc()), cpuStr);
1013}
1014
1015cir::GetGlobalOp CIRGenFunction::createGetCpuModel(mlir::Location loc) {
1016 mlir::Type u32 = builder.getUInt32Ty();
1017 auto cpuModel =
1018 mlir::dyn_cast_or_null<cir::GlobalOp>(cgm.getGlobalValue("__cpu_model"));
1019
1020 if (!cpuModel) {
1021 // Matching the struct layout from the compiler-rt/libgcc structure that is
1022 // filled in:
1023 // unsigned int __cpu_vendor;
1024 // unsigned int __cpu_type;
1025 // unsigned int __cpu_subtype;
1026 // unsigned int __cpu_features[1];
1027 mlir::Type tys[] = {u32, u32, u32, cir::ArrayType::get(u32, 1)};
1028 mlir::Type modelTy = builder.getAnonRecordTy(
1029 tys, /*packed=*/false, cir::RecordType::getAllDataKinds(tys));
1030 cpuModel =
1031 cgm.createGlobalOp(loc, "__cpu_model", modelTy, /*isConstant=*/false);
1032 cpuModel.setDsoLocal(true);
1033 }
1034
1035 return cir::GetGlobalOp::create(builder, loc,
1036 builder.getPointerTo(cpuModel.getSymType()),
1037 cpuModel.getSymName());
1038}
1039
1040cir::GetGlobalOp CIRGenFunction::createGetCpuFeatures2(mlir::Location loc) {
1041 mlir::Type u32 = builder.getUInt32Ty();
1042 auto cpuFeatures2 = mlir::dyn_cast_or_null<cir::GlobalOp>(
1043 cgm.getGlobalValue("__cpu_features2"));
1044
1045 if (!cpuFeatures2) {
1046 // This is just an array of 3 uint32s.
1047 mlir::Type arrTy = cir::ArrayType::get(u32, 3);
1048 cpuFeatures2 =
1049 cgm.createGlobalOp(loc, "__cpu_features2", arrTy, /*isConstant=*/false);
1050 cpuFeatures2.setDsoLocal(true);
1051 }
1052
1053 return cir::GetGlobalOp::create(
1054 builder, loc, builder.getPointerTo(cpuFeatures2.getSymType()),
1055 cpuFeatures2.getSymName());
1056}
1057
1058mlir::Value CIRGenFunction::emitX86CpuIs(mlir::Location loc, StringRef cpuStr) {
1059 mlir::Type u32 = builder.getUInt32Ty();
1060 // Calculate the index needed to access the correct field based on the
1061 // range. ABI_VALUE matches with compiler-rt/libgcc values.
1062 auto [fieldName, index, value] =
1063 llvm::StringSwitch<std::tuple<llvm::StringLiteral, unsigned, unsigned>>(
1064 cpuStr)
1065#define X86_VENDOR(ENUM, STRING, ABI_VALUE) \
1066 .Case(STRING, {"__cpu_vendor", 0u, ABI_VALUE})
1067#define X86_CPU_TYPE(ENUM, STR, ABI_VALUE) \
1068 .Case(STR, {"__cpu_type", 1u, ABI_VALUE})
1069#define X86_CPU_SUBTYPE(ENUM, STR, ABI_VALUE) \
1070 .Case(STR, {"__cpu_subtype", 2u, ABI_VALUE})
1071#include "llvm/TargetParser/X86TargetParser.def"
1072 .Default({"", 0, 0});
1073 assert(value != 0 && "Invalid CPUStr passed to CpuIs");
1074
1075 cir::GetGlobalOp getCpuModel = createGetCpuModel(loc);
1076
1077 // Note: the StringSwitch above ONLY has the ability to get the first 3
1078 // fields, so we don't have to worry about it being the array field. So we
1079 // can continue assuming everything is an int.
1080 cir::GetMemberOp cpuValuePtr = builder.createGetMember(
1081 loc, builder.getPointerTo(u32), getCpuModel, fieldName, index);
1082 cir::LoadOp getVal = builder.createAlignedLoad(loc, u32, cpuValuePtr,
1084
1085 return cir::CmpOp::create(builder, loc, cir::CmpOpKind::eq, getVal,
1086 builder.getUInt32(value, loc));
1087}
1088
1090 const Expr *featureExpr = expr->getArg(0)->IgnoreParenCasts();
1091 StringRef featureStr = cast<StringLiteral>(featureExpr)->getString();
1092 if (!getContext().getTargetInfo().validateCpuSupports(featureStr))
1093 return builder.getFalse(getLoc(expr->getExprLoc()));
1094 return emitX86CpuSupports(getLoc(expr->getExprLoc()), featureStr);
1095}
1096
1097mlir::Value
1099 ArrayRef<StringRef> featureStrs) {
1100 return emitX86CpuSupports(loc, llvm::X86::getCpuSupportsMask(featureStrs));
1101}
1102
1103mlir::Value
1105 std::array<uint32_t, 4> featureMask) {
1106 mlir::Type u32 = builder.getUInt32Ty();
1107 mlir::Value result;
1108
1109 auto addCondition = [&](unsigned maskVal, mlir::Value features) {
1110 cir::ConstantOp mask = builder.getUInt32(maskVal, loc);
1111 mlir::Value bitset = builder.createAnd(loc, features, mask);
1112 mlir::Value cmp =
1113 cir::CmpOp::create(builder, loc, cir::CmpOpKind::eq, bitset, mask);
1114
1115 if (result)
1116 result = builder.createAnd(loc, result, cmp);
1117 else
1118 result = cmp;
1119 };
1120
1121 // only check the '__cpu_features[0]' if we have a non-zero value. A zero
1122 // here means to JUST check __cpu_features2.
1123 if (featureMask[0] != 0) {
1124 cir::GetGlobalOp getCpuModel = createGetCpuModel(loc);
1125 mlir::Type u32 = builder.getUInt32Ty();
1126 auto arrTy = cir::ArrayType::get(u32, 1);
1127
1128 // Pick out the __cpu_features field, the 4th field in the struct.
1129 cir::GetMemberOp cpuFeatArrPtr = builder.createGetMember(
1130 loc, builder.getPointerTo(arrTy), getCpuModel, "__cpu_features", 3);
1131
1132 mlir::Value cpuFeatVal = builder.getArrayElement(
1133 loc, loc, cpuFeatArrPtr, arrTy,
1134 /*index=*/builder.getUInt32(0, loc), /*shouldDecay=*/true);
1135 cir::LoadOp features = builder.createAlignedLoad(
1136 loc, u32, cpuFeatVal, CharUnits::fromQuantity(4));
1137
1138 addCondition(featureMask[0], features);
1139 }
1140
1141 // the 0th index is looked up in the __cpu_model field, the rest come from an
1142 // array.
1143 cir::GetGlobalOp getCpuFeatures2; // = createGetCpuFeatures2(loc);
1144 for (int i = 1; i != 4; ++i) {
1145 const uint32_t val = featureMask[i];
1146 if (!val)
1147 continue;
1148 if (!getCpuFeatures2)
1149 getCpuFeatures2 = createGetCpuFeatures2(loc);
1150 mlir::Value getArrayElt = builder.getArrayElement(
1151 loc, loc, getCpuFeatures2,
1152 cast<cir::PointerType>(getCpuFeatures2.getType()).getPointee(),
1153 builder.getUInt32(/*index=*/i - 1, loc),
1154 /*shouldDecay=*/true);
1155 cir::LoadOp features = builder.createAlignedLoad(
1156 loc, u32, getArrayElt, CharUnits::fromQuantity(4));
1157
1158 addCondition(val, features);
1159 }
1160
1161 return result;
1162}
1163
1164mlir::Value CIRGenFunction::emitX86CpuInit(mlir::Location loc) {
1165 cir::FuncOp initFunc =
1166 cgm.createRuntimeFunction(builder.getVoidFnTy(), "__cpu_indicator_init");
1167 initFunc.setDsoLocal(true);
1169
1170 return builder.createCallOp(loc, initFunc, {}).getResult();
1171}
1172
1173std::optional<mlir::Value>
1175 if (builtinID == Builtin::BI__builtin_cpu_is)
1176 return emitX86CpuIs(expr);
1177 if (builtinID == Builtin::BI__builtin_cpu_supports)
1178 return emitX86CpuSupports(expr);
1179 if (builtinID == Builtin::BI__builtin_cpu_init)
1180 return emitX86CpuInit(getLoc(expr->getExprLoc()));
1181
1182 // Handle MSVC intrinsics before argument evaluation to prevent double
1183 // evaluation.
1185
1186 // Find out if any arguments are required to be integer constant expressions.
1188
1189 // The operands of the builtin call
1191
1192 // `ICEArguments` is a bitmap indicating whether the argument at the i-th bit
1193 // is required to be a constant integer expression.
1194 unsigned iceArguments = 0;
1196 getContext().GetBuiltinType(builtinID, error, &iceArguments);
1197 assert(error == ASTContext::GE_None && "Error while getting builtin type.");
1198
1199 for (auto [idx, arg] : llvm::enumerate(expr->arguments()))
1200 ops.push_back(emitScalarOrConstFoldImmArg(iceArguments, idx, arg));
1201
1202 CIRGenBuilderTy &builder = getBuilder();
1203 mlir::Type voidTy = builder.getVoidTy();
1204
1205 switch (builtinID) {
1206 default:
1207 return std::nullopt;
1208 case X86::BI_mm_clflush:
1209 return builder.emitIntrinsicCallOp(getLoc(expr->getExprLoc()),
1210 "x86.sse2.clflush", voidTy, ops[0]);
1211 case X86::BI_mm_lfence:
1212 return builder.emitIntrinsicCallOp(getLoc(expr->getExprLoc()),
1213 "x86.sse2.lfence", voidTy);
1214 case X86::BI_mm_pause:
1215 return builder.emitIntrinsicCallOp(getLoc(expr->getExprLoc()),
1216 "x86.sse2.pause", voidTy);
1217 case X86::BI_mm_mfence:
1218 return builder.emitIntrinsicCallOp(getLoc(expr->getExprLoc()),
1219 "x86.sse2.mfence", voidTy);
1220 case X86::BI_mm_sfence:
1221 return builder.emitIntrinsicCallOp(getLoc(expr->getExprLoc()),
1222 "x86.sse.sfence", voidTy);
1223 case X86::BI_mm_prefetch:
1224 case X86::BI_m_prefetch:
1225 case X86::BI_m_prefetchw:
1226 return emitPrefetch(*this, builtinID, expr, ops);
1227 case X86::BI__rdtsc:
1228 return builder.emitIntrinsicCallOp(getLoc(expr->getExprLoc()), "x86.rdtsc",
1229 builder.getUInt64Ty());
1230 case X86::BI__builtin_ia32_rdtscp: {
1231 mlir::Location loc = getLoc(expr->getExprLoc());
1232 mlir::Type i64Ty = builder.getUInt64Ty();
1233 mlir::Type i32Ty = builder.getUInt32Ty();
1234 mlir::Type members[] = {i64Ty, i32Ty};
1235 mlir::Type structTy = builder.getAnonRecordTy(
1236 members, /*packed=*/false, cir::RecordType::getAllDataKinds(members));
1237 mlir::Value result =
1238 builder.emitIntrinsicCallOp(loc, "x86.rdtscp", structTy);
1239
1240 // Extract and store processor_id (element 1 of the returned struct)
1241 mlir::Value processorId =
1242 cir::ExtractMemberOp::create(builder, loc, i32Ty, result, 1);
1243 // ops[0] is the address to store the processor ID
1244 builder.createStore(loc, processorId, Address{ops[0], CharUnits::One()});
1245
1246 // Return timestamp (element 0 of the returned struct)
1247 return cir::ExtractMemberOp::create(builder, loc, i64Ty, result, 0);
1248 }
1249 case X86::BI__builtin_ia32_roundps:
1250 case X86::BI__builtin_ia32_roundpd:
1251 case X86::BI__builtin_ia32_roundps256:
1252 case X86::BI__builtin_ia32_roundpd256:
1253 case X86::BI__builtin_ia32_roundss:
1254 case X86::BI__builtin_ia32_roundsd:
1255 return emitX86Round(*this, builtinID, expr, ops);
1256 case X86::BI__builtin_ia32_lzcnt_u16:
1257 case X86::BI__builtin_ia32_lzcnt_u32:
1258 case X86::BI__builtin_ia32_lzcnt_u64:
1259 return cir::BitClzOp::create(builder, getLoc(expr->getExprLoc()), ops[0],
1260 /*poisonZero=*/false)
1261 .getResult();
1262 case X86::BI__builtin_ia32_tzcnt_u16:
1263 case X86::BI__builtin_ia32_tzcnt_u32:
1264 case X86::BI__builtin_ia32_tzcnt_u64:
1265 return cir::BitCtzOp::create(builder, getLoc(expr->getExprLoc()), ops[0],
1266 /*poisonZero=*/false)
1267 .getResult();
1268 case X86::BI__builtin_ia32_undef128:
1269 case X86::BI__builtin_ia32_undef256:
1270 case X86::BI__builtin_ia32_undef512:
1271 // The x86 definition of "undef" is not the same as the LLVM definition
1272 // (PR32176). We leave optimizing away an unnecessary zero constant to the
1273 // IR optimizer and backend.
1274 // TODO: If we had a "freeze" IR instruction to generate a fixed undef
1275 // value, we should use that here instead of a zero.
1276 return builder.getNullValue(convertType(expr->getType()),
1277 getLoc(expr->getExprLoc()));
1278 case X86::BI__builtin_ia32_vec_ext_v4hi:
1279 case X86::BI__builtin_ia32_vec_ext_v16qi:
1280 case X86::BI__builtin_ia32_vec_ext_v8hi:
1281 case X86::BI__builtin_ia32_vec_ext_v4si:
1282 case X86::BI__builtin_ia32_vec_ext_v4sf:
1283 case X86::BI__builtin_ia32_vec_ext_v2di:
1284 case X86::BI__builtin_ia32_vec_ext_v32qi:
1285 case X86::BI__builtin_ia32_vec_ext_v16hi:
1286 case X86::BI__builtin_ia32_vec_ext_v8si:
1287 case X86::BI__builtin_ia32_vec_ext_v4di: {
1288 unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize();
1289
1290 uint64_t index = getZExtIntValueFromConstOp(ops[1]);
1291 index &= numElts - 1;
1292
1293 cir::ConstantOp indexVal =
1294 builder.getUInt64(index, getLoc(expr->getExprLoc()));
1295
1296 // These builtins exist so we can ensure the index is an ICE and in range.
1297 // Otherwise we could just do this in the header file.
1298 return cir::VecExtractOp::create(builder, getLoc(expr->getExprLoc()),
1299 ops[0], indexVal);
1300 }
1301 case X86::BI__builtin_ia32_vec_set_v4hi:
1302 case X86::BI__builtin_ia32_vec_set_v16qi:
1303 case X86::BI__builtin_ia32_vec_set_v8hi:
1304 case X86::BI__builtin_ia32_vec_set_v4si:
1305 case X86::BI__builtin_ia32_vec_set_v2di:
1306 case X86::BI__builtin_ia32_vec_set_v32qi:
1307 case X86::BI__builtin_ia32_vec_set_v16hi:
1308 case X86::BI__builtin_ia32_vec_set_v8si:
1309 case X86::BI__builtin_ia32_vec_set_v4di: {
1310 return emitVecInsert(builder, getLoc(expr->getExprLoc()), ops[0], ops[1],
1311 ops[2]);
1312 }
1313 case X86::BI__builtin_ia32_kunpckhi:
1314 return emitX86MaskUnpack(builder, getLoc(expr->getExprLoc()),
1315 "x86.avx512.kunpackb", ops);
1316 case X86::BI__builtin_ia32_kunpcksi:
1317 return emitX86MaskUnpack(builder, getLoc(expr->getExprLoc()),
1318 "x86.avx512.kunpackw", ops);
1319 case X86::BI__builtin_ia32_kunpckdi:
1320 return emitX86MaskUnpack(builder, getLoc(expr->getExprLoc()),
1321 "x86.avx512.kunpackd", ops);
1322 case X86::BI_mm_setcsr:
1323 case X86::BI__builtin_ia32_ldmxcsr: {
1324 mlir::Location loc = getLoc(expr->getExprLoc());
1325 Address tmp = createMemTemp(expr->getArg(0)->getType(), loc);
1326 builder.createStore(loc, ops[0], tmp);
1327 return builder.emitIntrinsicCallOp(loc, "x86.sse.ldmxcsr",
1328 builder.getVoidTy(), tmp.getPointer());
1329 }
1330 case X86::BI_mm_getcsr:
1331 case X86::BI__builtin_ia32_stmxcsr: {
1332 mlir::Location loc = getLoc(expr->getExprLoc());
1333 Address tmp = createMemTemp(expr->getType(), loc);
1334 builder.emitIntrinsicCallOp(loc, "x86.sse.stmxcsr", builder.getVoidTy(),
1335 tmp.getPointer());
1336 return builder.createLoad(loc, tmp);
1337 }
1338 case X86::BI__builtin_ia32_xsave:
1339 case X86::BI__builtin_ia32_xsave64:
1340 case X86::BI__builtin_ia32_xrstor:
1341 case X86::BI__builtin_ia32_xrstor64:
1342 case X86::BI__builtin_ia32_xsaveopt:
1343 case X86::BI__builtin_ia32_xsaveopt64:
1344 case X86::BI__builtin_ia32_xrstors:
1345 case X86::BI__builtin_ia32_xrstors64:
1346 case X86::BI__builtin_ia32_xsavec:
1347 case X86::BI__builtin_ia32_xsavec64:
1348 case X86::BI__builtin_ia32_xsaves:
1349 case X86::BI__builtin_ia32_xsaves64:
1350 case X86::BI__builtin_ia32_xsetbv:
1351 case X86::BI_xsetbv: {
1352 mlir::Location loc = getLoc(expr->getExprLoc());
1353 StringRef intrinsicName;
1354 switch (builtinID) {
1355 default:
1356 llvm_unreachable("Unexpected builtin");
1357 case X86::BI__builtin_ia32_xsave:
1358 intrinsicName = "x86.xsave";
1359 break;
1360 case X86::BI__builtin_ia32_xsave64:
1361 intrinsicName = "x86.xsave64";
1362 break;
1363 case X86::BI__builtin_ia32_xrstor:
1364 intrinsicName = "x86.xrstor";
1365 break;
1366 case X86::BI__builtin_ia32_xrstor64:
1367 intrinsicName = "x86.xrstor64";
1368 break;
1369 case X86::BI__builtin_ia32_xsaveopt:
1370 intrinsicName = "x86.xsaveopt";
1371 break;
1372 case X86::BI__builtin_ia32_xsaveopt64:
1373 intrinsicName = "x86.xsaveopt64";
1374 break;
1375 case X86::BI__builtin_ia32_xrstors:
1376 intrinsicName = "x86.xrstors";
1377 break;
1378 case X86::BI__builtin_ia32_xrstors64:
1379 intrinsicName = "x86.xrstors64";
1380 break;
1381 case X86::BI__builtin_ia32_xsavec:
1382 intrinsicName = "x86.xsavec";
1383 break;
1384 case X86::BI__builtin_ia32_xsavec64:
1385 intrinsicName = "x86.xsavec64";
1386 break;
1387 case X86::BI__builtin_ia32_xsaves:
1388 intrinsicName = "x86.xsaves";
1389 break;
1390 case X86::BI__builtin_ia32_xsaves64:
1391 intrinsicName = "x86.xsaves64";
1392 break;
1393 case X86::BI__builtin_ia32_xsetbv:
1394 case X86::BI_xsetbv:
1395 intrinsicName = "x86.xsetbv";
1396 break;
1397 }
1398
1399 // The xsave family of instructions take a 64-bit mask that specifies
1400 // which processor state components to save/restore. The hardware expects
1401 // this mask split into two 32-bit registers: EDX (high 32 bits) and
1402 // EAX (low 32 bits).
1403 mlir::Type i32Ty = builder.getSInt32Ty();
1404
1405 // Mhi = (uint32_t)(ops[1] >> 32) - extract high 32 bits via right shift
1406 cir::ConstantOp shift32 = builder.getSInt64(32, loc);
1407 mlir::Value mhi = builder.createShift(loc, ops[1], shift32.getResult(),
1408 /*isShiftLeft=*/false);
1409 mhi = builder.createIntCast(mhi, i32Ty);
1410
1411 // Mlo = (uint32_t)ops[1] - extract low 32 bits by truncation
1412 mlir::Value mlo = builder.createIntCast(ops[1], i32Ty);
1413
1414 return builder.emitIntrinsicCallOp(loc, intrinsicName, voidTy,
1415 mlir::ValueRange{ops[0], mhi, mlo});
1416 }
1417 case X86::BI__builtin_ia32_xgetbv:
1418 case X86::BI_xgetbv:
1419 // xgetbv reads the extended control register specified by ops[0] (ECX)
1420 // and returns the 64-bit value
1421 return builder.emitIntrinsicCallOp(getLoc(expr->getExprLoc()), "x86.xgetbv",
1422 builder.getUInt64Ty(), ops[0]);
1423 case X86::BI__builtin_ia32_storedqudi128_mask:
1424 case X86::BI__builtin_ia32_storedqusi128_mask:
1425 case X86::BI__builtin_ia32_storedquhi128_mask:
1426 case X86::BI__builtin_ia32_storedquqi128_mask:
1427 case X86::BI__builtin_ia32_storeupd128_mask:
1428 case X86::BI__builtin_ia32_storeups128_mask:
1429 case X86::BI__builtin_ia32_storedqudi256_mask:
1430 case X86::BI__builtin_ia32_storedqusi256_mask:
1431 case X86::BI__builtin_ia32_storedquhi256_mask:
1432 case X86::BI__builtin_ia32_storedquqi256_mask:
1433 case X86::BI__builtin_ia32_storeupd256_mask:
1434 case X86::BI__builtin_ia32_storeups256_mask:
1435 case X86::BI__builtin_ia32_storedqudi512_mask:
1436 case X86::BI__builtin_ia32_storedqusi512_mask:
1437 case X86::BI__builtin_ia32_storedquhi512_mask:
1438 case X86::BI__builtin_ia32_storedquqi512_mask:
1439 case X86::BI__builtin_ia32_storeupd512_mask:
1440 case X86::BI__builtin_ia32_storeups512_mask:
1441 case X86::BI__builtin_ia32_storesbf16128_mask:
1442 case X86::BI__builtin_ia32_storesh128_mask:
1443 case X86::BI__builtin_ia32_storess128_mask:
1444 case X86::BI__builtin_ia32_storesd128_mask:
1445 cgm.errorNYI(expr->getSourceRange(),
1446 std::string("unimplemented x86 builtin call: ") +
1447 getContext().BuiltinInfo.getName(builtinID));
1448 return mlir::Value{};
1449 case X86::BI__builtin_ia32_cvtmask2b128:
1450 case X86::BI__builtin_ia32_cvtmask2b256:
1451 case X86::BI__builtin_ia32_cvtmask2b512:
1452 case X86::BI__builtin_ia32_cvtmask2w128:
1453 case X86::BI__builtin_ia32_cvtmask2w256:
1454 case X86::BI__builtin_ia32_cvtmask2w512:
1455 case X86::BI__builtin_ia32_cvtmask2d128:
1456 case X86::BI__builtin_ia32_cvtmask2d256:
1457 case X86::BI__builtin_ia32_cvtmask2d512:
1458 case X86::BI__builtin_ia32_cvtmask2q128:
1459 case X86::BI__builtin_ia32_cvtmask2q256:
1460 case X86::BI__builtin_ia32_cvtmask2q512:
1461 return emitX86SExtMask(this->getBuilder(), ops[0],
1462 convertType(expr->getType()),
1463 getLoc(expr->getExprLoc()));
1464 case X86::BI__builtin_ia32_cvtb2mask128:
1465 case X86::BI__builtin_ia32_cvtb2mask256:
1466 case X86::BI__builtin_ia32_cvtb2mask512:
1467 case X86::BI__builtin_ia32_cvtw2mask128:
1468 case X86::BI__builtin_ia32_cvtw2mask256:
1469 case X86::BI__builtin_ia32_cvtw2mask512:
1470 case X86::BI__builtin_ia32_cvtd2mask128:
1471 case X86::BI__builtin_ia32_cvtd2mask256:
1472 case X86::BI__builtin_ia32_cvtd2mask512:
1473 case X86::BI__builtin_ia32_cvtq2mask128:
1474 case X86::BI__builtin_ia32_cvtq2mask256:
1475 case X86::BI__builtin_ia32_cvtq2mask512:
1476 return emitX86ConvertToMask(*this, this->getBuilder(), ops[0],
1477 getLoc(expr->getExprLoc()));
1478 case X86::BI__builtin_ia32_cvtdq2ps512_mask:
1479 case X86::BI__builtin_ia32_cvtqq2ps512_mask:
1480 case X86::BI__builtin_ia32_cvtqq2pd512_mask:
1481 case X86::BI__builtin_ia32_vcvtw2ph512_mask:
1482 case X86::BI__builtin_ia32_vcvtdq2ph512_mask:
1483 case X86::BI__builtin_ia32_vcvtqq2ph512_mask:
1484 case X86::BI__builtin_ia32_cvtudq2ps512_mask:
1485 case X86::BI__builtin_ia32_cvtuqq2ps512_mask:
1486 case X86::BI__builtin_ia32_cvtuqq2pd512_mask:
1487 case X86::BI__builtin_ia32_vcvtuw2ph512_mask:
1488 case X86::BI__builtin_ia32_vcvtudq2ph512_mask:
1489 case X86::BI__builtin_ia32_vcvtuqq2ph512_mask:
1490 case X86::BI__builtin_ia32_vfmaddsh3_mask:
1491 case X86::BI__builtin_ia32_vfmaddss3_mask:
1492 case X86::BI__builtin_ia32_vfmaddsd3_mask:
1493 case X86::BI__builtin_ia32_vfmaddsh3_maskz:
1494 case X86::BI__builtin_ia32_vfmaddss3_maskz:
1495 case X86::BI__builtin_ia32_vfmaddsd3_maskz:
1496 case X86::BI__builtin_ia32_vfmaddsh3_mask3:
1497 case X86::BI__builtin_ia32_vfmaddss3_mask3:
1498 case X86::BI__builtin_ia32_vfmaddsd3_mask3:
1499 case X86::BI__builtin_ia32_vfmsubsh3_mask3:
1500 case X86::BI__builtin_ia32_vfmsubss3_mask3:
1501 case X86::BI__builtin_ia32_vfmsubsd3_mask3:
1502 case X86::BI__builtin_ia32_vfmaddph512_mask:
1503 case X86::BI__builtin_ia32_vfmaddph512_maskz:
1504 case X86::BI__builtin_ia32_vfmaddph512_mask3:
1505 case X86::BI__builtin_ia32_vfmaddps512_mask:
1506 case X86::BI__builtin_ia32_vfmaddps512_maskz:
1507 case X86::BI__builtin_ia32_vfmaddps512_mask3:
1508 case X86::BI__builtin_ia32_vfmsubps512_mask3:
1509 case X86::BI__builtin_ia32_vfmaddpd512_mask:
1510 case X86::BI__builtin_ia32_vfmaddpd512_maskz:
1511 case X86::BI__builtin_ia32_vfmaddpd512_mask3:
1512 case X86::BI__builtin_ia32_vfmsubpd512_mask3:
1513 case X86::BI__builtin_ia32_vfmsubph512_mask3:
1514 case X86::BI__builtin_ia32_vfmaddsubph512_mask:
1515 case X86::BI__builtin_ia32_vfmaddsubph512_maskz:
1516 case X86::BI__builtin_ia32_vfmaddsubph512_mask3:
1517 case X86::BI__builtin_ia32_vfmsubaddph512_mask3:
1518 case X86::BI__builtin_ia32_vfmaddsubps512_mask:
1519 case X86::BI__builtin_ia32_vfmaddsubps512_maskz:
1520 case X86::BI__builtin_ia32_vfmaddsubps512_mask3:
1521 case X86::BI__builtin_ia32_vfmsubaddps512_mask3:
1522 case X86::BI__builtin_ia32_vfmaddsubpd512_mask:
1523 case X86::BI__builtin_ia32_vfmaddsubpd512_maskz:
1524 case X86::BI__builtin_ia32_vfmaddsubpd512_mask3:
1525 case X86::BI__builtin_ia32_vfmsubaddpd512_mask3:
1526 case X86::BI__builtin_ia32_movdqa32store128_mask:
1527 case X86::BI__builtin_ia32_movdqa64store128_mask:
1528 case X86::BI__builtin_ia32_storeaps128_mask:
1529 case X86::BI__builtin_ia32_storeapd128_mask:
1530 case X86::BI__builtin_ia32_movdqa32store256_mask:
1531 case X86::BI__builtin_ia32_movdqa64store256_mask:
1532 case X86::BI__builtin_ia32_storeaps256_mask:
1533 case X86::BI__builtin_ia32_storeapd256_mask:
1534 case X86::BI__builtin_ia32_movdqa32store512_mask:
1535 case X86::BI__builtin_ia32_movdqa64store512_mask:
1536 case X86::BI__builtin_ia32_storeaps512_mask:
1537 case X86::BI__builtin_ia32_storeapd512_mask:
1538 cgm.errorNYI(expr->getSourceRange(),
1539 std::string("unimplemented X86 builtin call: ") +
1540 getContext().BuiltinInfo.getName(builtinID));
1541 return {};
1542
1543 case X86::BI__builtin_ia32_loadups128_mask:
1544 case X86::BI__builtin_ia32_loadups256_mask:
1545 case X86::BI__builtin_ia32_loadups512_mask:
1546 case X86::BI__builtin_ia32_loadupd128_mask:
1547 case X86::BI__builtin_ia32_loadupd256_mask:
1548 case X86::BI__builtin_ia32_loadupd512_mask:
1549 case X86::BI__builtin_ia32_loaddquqi128_mask:
1550 case X86::BI__builtin_ia32_loaddquqi256_mask:
1551 case X86::BI__builtin_ia32_loaddquqi512_mask:
1552 case X86::BI__builtin_ia32_loaddquhi128_mask:
1553 case X86::BI__builtin_ia32_loaddquhi256_mask:
1554 case X86::BI__builtin_ia32_loaddquhi512_mask:
1555 case X86::BI__builtin_ia32_loaddqusi128_mask:
1556 case X86::BI__builtin_ia32_loaddqusi256_mask:
1557 case X86::BI__builtin_ia32_loaddqusi512_mask:
1558 case X86::BI__builtin_ia32_loaddqudi128_mask:
1559 case X86::BI__builtin_ia32_loaddqudi256_mask:
1560 case X86::BI__builtin_ia32_loaddqudi512_mask:
1561 case X86::BI__builtin_ia32_loadsbf16128_mask:
1562 case X86::BI__builtin_ia32_loadsh128_mask:
1563 case X86::BI__builtin_ia32_loadss128_mask:
1564 case X86::BI__builtin_ia32_loadsd128_mask:
1565 return emitX86MaskedLoad(builder, ops, llvm::Align(1),
1566 getLoc(expr->getExprLoc()));
1567
1568 case X86::BI__builtin_ia32_loadaps128_mask:
1569 case X86::BI__builtin_ia32_loadaps256_mask:
1570 case X86::BI__builtin_ia32_loadaps512_mask:
1571 case X86::BI__builtin_ia32_loadapd128_mask:
1572 case X86::BI__builtin_ia32_loadapd256_mask:
1573 case X86::BI__builtin_ia32_loadapd512_mask:
1574 case X86::BI__builtin_ia32_movdqa32load128_mask:
1575 case X86::BI__builtin_ia32_movdqa32load256_mask:
1576 case X86::BI__builtin_ia32_movdqa32load512_mask:
1577 case X86::BI__builtin_ia32_movdqa64load128_mask:
1578 case X86::BI__builtin_ia32_movdqa64load256_mask:
1579 case X86::BI__builtin_ia32_movdqa64load512_mask:
1580 return emitX86MaskedLoad(
1581 builder, ops,
1582 getContext()
1583 .getTypeAlignInChars(expr->getArg(1)->getType())
1584 .getAsAlign(),
1585 getLoc(expr->getExprLoc()));
1586
1587 case X86::BI__builtin_ia32_expandloaddf128_mask:
1588 case X86::BI__builtin_ia32_expandloaddf256_mask:
1589 case X86::BI__builtin_ia32_expandloaddf512_mask:
1590 case X86::BI__builtin_ia32_expandloadsf128_mask:
1591 case X86::BI__builtin_ia32_expandloadsf256_mask:
1592 case X86::BI__builtin_ia32_expandloadsf512_mask:
1593 case X86::BI__builtin_ia32_expandloaddi128_mask:
1594 case X86::BI__builtin_ia32_expandloaddi256_mask:
1595 case X86::BI__builtin_ia32_expandloaddi512_mask:
1596 case X86::BI__builtin_ia32_expandloadsi128_mask:
1597 case X86::BI__builtin_ia32_expandloadsi256_mask:
1598 case X86::BI__builtin_ia32_expandloadsi512_mask:
1599 case X86::BI__builtin_ia32_expandloadhi128_mask:
1600 case X86::BI__builtin_ia32_expandloadhi256_mask:
1601 case X86::BI__builtin_ia32_expandloadhi512_mask:
1602 case X86::BI__builtin_ia32_expandloadqi128_mask:
1603 case X86::BI__builtin_ia32_expandloadqi256_mask:
1604 case X86::BI__builtin_ia32_expandloadqi512_mask: {
1605 cgm.errorNYI(expr->getSourceRange(),
1606 std::string("unimplemented X86 builtin call: ") +
1607 getContext().BuiltinInfo.getName(builtinID));
1608 return {};
1609 }
1610 case X86::BI__builtin_ia32_compressstoredf128_mask:
1611 case X86::BI__builtin_ia32_compressstoredf256_mask:
1612 case X86::BI__builtin_ia32_compressstoredf512_mask:
1613 case X86::BI__builtin_ia32_compressstoresf128_mask:
1614 case X86::BI__builtin_ia32_compressstoresf256_mask:
1615 case X86::BI__builtin_ia32_compressstoresf512_mask:
1616 case X86::BI__builtin_ia32_compressstoredi128_mask:
1617 case X86::BI__builtin_ia32_compressstoredi256_mask:
1618 case X86::BI__builtin_ia32_compressstoredi512_mask:
1619 case X86::BI__builtin_ia32_compressstoresi128_mask:
1620 case X86::BI__builtin_ia32_compressstoresi256_mask:
1621 case X86::BI__builtin_ia32_compressstoresi512_mask:
1622 case X86::BI__builtin_ia32_compressstorehi128_mask:
1623 case X86::BI__builtin_ia32_compressstorehi256_mask:
1624 case X86::BI__builtin_ia32_compressstorehi512_mask:
1625 case X86::BI__builtin_ia32_compressstoreqi128_mask:
1626 case X86::BI__builtin_ia32_compressstoreqi256_mask:
1627 case X86::BI__builtin_ia32_compressstoreqi512_mask:
1628 return emitX86CompressStore(builder, getLoc(expr->getExprLoc()), ops);
1629 case X86::BI__builtin_ia32_expanddf128_mask:
1630 case X86::BI__builtin_ia32_expanddf256_mask:
1631 case X86::BI__builtin_ia32_expanddf512_mask:
1632 case X86::BI__builtin_ia32_expandsf128_mask:
1633 case X86::BI__builtin_ia32_expandsf256_mask:
1634 case X86::BI__builtin_ia32_expandsf512_mask:
1635 case X86::BI__builtin_ia32_expanddi128_mask:
1636 case X86::BI__builtin_ia32_expanddi256_mask:
1637 case X86::BI__builtin_ia32_expanddi512_mask:
1638 case X86::BI__builtin_ia32_expandsi128_mask:
1639 case X86::BI__builtin_ia32_expandsi256_mask:
1640 case X86::BI__builtin_ia32_expandsi512_mask:
1641 case X86::BI__builtin_ia32_expandhi128_mask:
1642 case X86::BI__builtin_ia32_expandhi256_mask:
1643 case X86::BI__builtin_ia32_expandhi512_mask:
1644 case X86::BI__builtin_ia32_expandqi128_mask:
1645 case X86::BI__builtin_ia32_expandqi256_mask:
1646 case X86::BI__builtin_ia32_expandqi512_mask: {
1647 mlir::Location loc = getLoc(expr->getExprLoc());
1648 return emitX86CompressExpand(builder, loc, ops[0], ops[1], ops[2],
1649 "x86.avx512.mask.expand");
1650 }
1651 case X86::BI__builtin_ia32_compressdf128_mask:
1652 case X86::BI__builtin_ia32_compressdf256_mask:
1653 case X86::BI__builtin_ia32_compressdf512_mask:
1654 case X86::BI__builtin_ia32_compresssf128_mask:
1655 case X86::BI__builtin_ia32_compresssf256_mask:
1656 case X86::BI__builtin_ia32_compresssf512_mask:
1657 case X86::BI__builtin_ia32_compressdi128_mask:
1658 case X86::BI__builtin_ia32_compressdi256_mask:
1659 case X86::BI__builtin_ia32_compressdi512_mask:
1660 case X86::BI__builtin_ia32_compresssi128_mask:
1661 case X86::BI__builtin_ia32_compresssi256_mask:
1662 case X86::BI__builtin_ia32_compresssi512_mask:
1663 case X86::BI__builtin_ia32_compresshi128_mask:
1664 case X86::BI__builtin_ia32_compresshi256_mask:
1665 case X86::BI__builtin_ia32_compresshi512_mask:
1666 case X86::BI__builtin_ia32_compressqi128_mask:
1667 case X86::BI__builtin_ia32_compressqi256_mask:
1668 case X86::BI__builtin_ia32_compressqi512_mask: {
1669 mlir::Location loc = getLoc(expr->getExprLoc());
1670 return emitX86CompressExpand(builder, loc, ops[0], ops[1], ops[2],
1671 "x86.avx512.mask.compress");
1672 }
1673 case X86::BI__builtin_ia32_gather3div2df:
1674 case X86::BI__builtin_ia32_gather3div2di:
1675 case X86::BI__builtin_ia32_gather3div4df:
1676 case X86::BI__builtin_ia32_gather3div4di:
1677 case X86::BI__builtin_ia32_gather3div4sf:
1678 case X86::BI__builtin_ia32_gather3div4si:
1679 case X86::BI__builtin_ia32_gather3div8sf:
1680 case X86::BI__builtin_ia32_gather3div8si:
1681 case X86::BI__builtin_ia32_gather3siv2df:
1682 case X86::BI__builtin_ia32_gather3siv2di:
1683 case X86::BI__builtin_ia32_gather3siv4df:
1684 case X86::BI__builtin_ia32_gather3siv4di:
1685 case X86::BI__builtin_ia32_gather3siv4sf:
1686 case X86::BI__builtin_ia32_gather3siv4si:
1687 case X86::BI__builtin_ia32_gather3siv8sf:
1688 case X86::BI__builtin_ia32_gather3siv8si:
1689 case X86::BI__builtin_ia32_gathersiv8df:
1690 case X86::BI__builtin_ia32_gathersiv16sf:
1691 case X86::BI__builtin_ia32_gatherdiv8df:
1692 case X86::BI__builtin_ia32_gatherdiv16sf:
1693 case X86::BI__builtin_ia32_gathersiv8di:
1694 case X86::BI__builtin_ia32_gathersiv16si:
1695 case X86::BI__builtin_ia32_gatherdiv8di:
1696 case X86::BI__builtin_ia32_gatherdiv16si: {
1697 StringRef intrinsicName;
1698 switch (builtinID) {
1699 default:
1700 llvm_unreachable("Unexpected builtin");
1701 case X86::BI__builtin_ia32_gather3div2df:
1702 intrinsicName = "x86.avx512.mask.gather3div2.df";
1703 break;
1704 case X86::BI__builtin_ia32_gather3div2di:
1705 intrinsicName = "x86.avx512.mask.gather3div2.di";
1706 break;
1707 case X86::BI__builtin_ia32_gather3div4df:
1708 intrinsicName = "x86.avx512.mask.gather3div4.df";
1709 break;
1710 case X86::BI__builtin_ia32_gather3div4di:
1711 intrinsicName = "x86.avx512.mask.gather3div4.di";
1712 break;
1713 case X86::BI__builtin_ia32_gather3div4sf:
1714 intrinsicName = "x86.avx512.mask.gather3div4.sf";
1715 break;
1716 case X86::BI__builtin_ia32_gather3div4si:
1717 intrinsicName = "x86.avx512.mask.gather3div4.si";
1718 break;
1719 case X86::BI__builtin_ia32_gather3div8sf:
1720 intrinsicName = "x86.avx512.mask.gather3div8.sf";
1721 break;
1722 case X86::BI__builtin_ia32_gather3div8si:
1723 intrinsicName = "x86.avx512.mask.gather3div8.si";
1724 break;
1725 case X86::BI__builtin_ia32_gather3siv2df:
1726 intrinsicName = "x86.avx512.mask.gather3siv2.df";
1727 break;
1728 case X86::BI__builtin_ia32_gather3siv2di:
1729 intrinsicName = "x86.avx512.mask.gather3siv2.di";
1730 break;
1731 case X86::BI__builtin_ia32_gather3siv4df:
1732 intrinsicName = "x86.avx512.mask.gather3siv4.df";
1733 break;
1734 case X86::BI__builtin_ia32_gather3siv4di:
1735 intrinsicName = "x86.avx512.mask.gather3siv4.di";
1736 break;
1737 case X86::BI__builtin_ia32_gather3siv4sf:
1738 intrinsicName = "x86.avx512.mask.gather3siv4.sf";
1739 break;
1740 case X86::BI__builtin_ia32_gather3siv4si:
1741 intrinsicName = "x86.avx512.mask.gather3siv4.si";
1742 break;
1743 case X86::BI__builtin_ia32_gather3siv8sf:
1744 intrinsicName = "x86.avx512.mask.gather3siv8.sf";
1745 break;
1746 case X86::BI__builtin_ia32_gather3siv8si:
1747 intrinsicName = "x86.avx512.mask.gather3siv8.si";
1748 break;
1749 case X86::BI__builtin_ia32_gathersiv8df:
1750 intrinsicName = "x86.avx512.mask.gather.dpd.512";
1751 break;
1752 case X86::BI__builtin_ia32_gathersiv16sf:
1753 intrinsicName = "x86.avx512.mask.gather.dps.512";
1754 break;
1755 case X86::BI__builtin_ia32_gatherdiv8df:
1756 intrinsicName = "x86.avx512.mask.gather.qpd.512";
1757 break;
1758 case X86::BI__builtin_ia32_gatherdiv16sf:
1759 intrinsicName = "x86.avx512.mask.gather.qps.512";
1760 break;
1761 case X86::BI__builtin_ia32_gathersiv8di:
1762 intrinsicName = "x86.avx512.mask.gather.dpq.512";
1763 break;
1764 case X86::BI__builtin_ia32_gathersiv16si:
1765 intrinsicName = "x86.avx512.mask.gather.dpi.512";
1766 break;
1767 case X86::BI__builtin_ia32_gatherdiv8di:
1768 intrinsicName = "x86.avx512.mask.gather.qpq.512";
1769 break;
1770 case X86::BI__builtin_ia32_gatherdiv16si:
1771 intrinsicName = "x86.avx512.mask.gather.qpi.512";
1772 break;
1773 }
1774
1775 mlir::Location loc = getLoc(expr->getExprLoc());
1776 unsigned minElts =
1777 std::min(cast<cir::VectorType>(ops[0].getType()).getSize(),
1778 cast<cir::VectorType>(ops[2].getType()).getSize());
1779 ops[3] = getMaskVecValue(builder, loc, ops[3], minElts);
1780 return builder.emitIntrinsicCallOp(loc, intrinsicName,
1781 convertType(expr->getType()), ops);
1782 }
1783 case X86::BI__builtin_ia32_scattersiv8df:
1784 case X86::BI__builtin_ia32_scattersiv16sf:
1785 case X86::BI__builtin_ia32_scatterdiv8df:
1786 case X86::BI__builtin_ia32_scatterdiv16sf:
1787 case X86::BI__builtin_ia32_scattersiv8di:
1788 case X86::BI__builtin_ia32_scattersiv16si:
1789 case X86::BI__builtin_ia32_scatterdiv8di:
1790 case X86::BI__builtin_ia32_scatterdiv16si:
1791 case X86::BI__builtin_ia32_scatterdiv2df:
1792 case X86::BI__builtin_ia32_scatterdiv2di:
1793 case X86::BI__builtin_ia32_scatterdiv4df:
1794 case X86::BI__builtin_ia32_scatterdiv4di:
1795 case X86::BI__builtin_ia32_scatterdiv4sf:
1796 case X86::BI__builtin_ia32_scatterdiv4si:
1797 case X86::BI__builtin_ia32_scatterdiv8sf:
1798 case X86::BI__builtin_ia32_scatterdiv8si:
1799 case X86::BI__builtin_ia32_scattersiv2df:
1800 case X86::BI__builtin_ia32_scattersiv2di:
1801 case X86::BI__builtin_ia32_scattersiv4df:
1802 case X86::BI__builtin_ia32_scattersiv4di:
1803 case X86::BI__builtin_ia32_scattersiv4sf:
1804 case X86::BI__builtin_ia32_scattersiv4si:
1805 case X86::BI__builtin_ia32_scattersiv8sf:
1806 case X86::BI__builtin_ia32_scattersiv8si: {
1807 llvm::StringRef intrinsicName;
1808 switch (builtinID) {
1809 default:
1810 llvm_unreachable("Unexpected builtin");
1811 case X86::BI__builtin_ia32_scattersiv8df:
1812 intrinsicName = "x86.avx512.mask.scatter.dpd.512";
1813 break;
1814 case X86::BI__builtin_ia32_scattersiv16sf:
1815 intrinsicName = "x86.avx512.mask.scatter.dps.512";
1816 break;
1817 case X86::BI__builtin_ia32_scatterdiv8df:
1818 intrinsicName = "x86.avx512.mask.scatter.qpd.512";
1819 break;
1820 case X86::BI__builtin_ia32_scatterdiv16sf:
1821 intrinsicName = "x86.avx512.mask.scatter.qps.512";
1822 break;
1823 case X86::BI__builtin_ia32_scattersiv8di:
1824 intrinsicName = "x86.avx512.mask.scatter.dpq.512";
1825 break;
1826 case X86::BI__builtin_ia32_scattersiv16si:
1827 intrinsicName = "x86.avx512.mask.scatter.dpi.512";
1828 break;
1829 case X86::BI__builtin_ia32_scatterdiv8di:
1830 intrinsicName = "x86.avx512.mask.scatter.qpq.512";
1831 break;
1832 case X86::BI__builtin_ia32_scatterdiv16si:
1833 intrinsicName = "x86.avx512.mask.scatter.qpi.512";
1834 break;
1835 case X86::BI__builtin_ia32_scatterdiv2df:
1836 intrinsicName = "x86.avx512.mask.scatterdiv2.df";
1837 break;
1838 case X86::BI__builtin_ia32_scatterdiv2di:
1839 intrinsicName = "x86.avx512.mask.scatterdiv2.di";
1840 break;
1841 case X86::BI__builtin_ia32_scatterdiv4df:
1842 intrinsicName = "x86.avx512.mask.scatterdiv4.df";
1843 break;
1844 case X86::BI__builtin_ia32_scatterdiv4di:
1845 intrinsicName = "x86.avx512.mask.scatterdiv4.di";
1846 break;
1847 case X86::BI__builtin_ia32_scatterdiv4sf:
1848 intrinsicName = "x86.avx512.mask.scatterdiv4.sf";
1849 break;
1850 case X86::BI__builtin_ia32_scatterdiv4si:
1851 intrinsicName = "x86.avx512.mask.scatterdiv4.si";
1852 break;
1853 case X86::BI__builtin_ia32_scatterdiv8sf:
1854 intrinsicName = "x86.avx512.mask.scatterdiv8.sf";
1855 break;
1856 case X86::BI__builtin_ia32_scatterdiv8si:
1857 intrinsicName = "x86.avx512.mask.scatterdiv8.si";
1858 break;
1859 case X86::BI__builtin_ia32_scattersiv2df:
1860 intrinsicName = "x86.avx512.mask.scattersiv2.df";
1861 break;
1862 case X86::BI__builtin_ia32_scattersiv2di:
1863 intrinsicName = "x86.avx512.mask.scattersiv2.di";
1864 break;
1865 case X86::BI__builtin_ia32_scattersiv4df:
1866 intrinsicName = "x86.avx512.mask.scattersiv4.df";
1867 break;
1868 case X86::BI__builtin_ia32_scattersiv4di:
1869 intrinsicName = "x86.avx512.mask.scattersiv4.di";
1870 break;
1871 case X86::BI__builtin_ia32_scattersiv4sf:
1872 intrinsicName = "x86.avx512.mask.scattersiv4.sf";
1873 break;
1874 case X86::BI__builtin_ia32_scattersiv4si:
1875 intrinsicName = "x86.avx512.mask.scattersiv4.si";
1876 break;
1877 case X86::BI__builtin_ia32_scattersiv8sf:
1878 intrinsicName = "x86.avx512.mask.scattersiv8.sf";
1879 break;
1880 case X86::BI__builtin_ia32_scattersiv8si:
1881 intrinsicName = "x86.avx512.mask.scattersiv8.si";
1882 break;
1883 }
1884
1885 mlir::Location loc = getLoc(expr->getExprLoc());
1886 unsigned minElts =
1887 std::min(cast<cir::VectorType>(ops[2].getType()).getSize(),
1888 cast<cir::VectorType>(ops[3].getType()).getSize());
1889 ops[1] = getMaskVecValue(builder, loc, ops[1], minElts);
1890
1891 return builder.emitIntrinsicCallOp(loc, intrinsicName,
1892 convertType(expr->getType()), ops);
1893 }
1894 case X86::BI__builtin_ia32_vextractf128_pd256:
1895 case X86::BI__builtin_ia32_vextractf128_ps256:
1896 case X86::BI__builtin_ia32_vextractf128_si256:
1897 case X86::BI__builtin_ia32_extract128i256:
1898 case X86::BI__builtin_ia32_extractf64x4_mask:
1899 case X86::BI__builtin_ia32_extractf32x4_mask:
1900 case X86::BI__builtin_ia32_extracti64x4_mask:
1901 case X86::BI__builtin_ia32_extracti32x4_mask:
1902 case X86::BI__builtin_ia32_extractf32x8_mask:
1903 case X86::BI__builtin_ia32_extracti32x8_mask:
1904 case X86::BI__builtin_ia32_extractf32x4_256_mask:
1905 case X86::BI__builtin_ia32_extracti32x4_256_mask:
1906 case X86::BI__builtin_ia32_extractf64x2_256_mask:
1907 case X86::BI__builtin_ia32_extracti64x2_256_mask:
1908 case X86::BI__builtin_ia32_extractf64x2_512_mask:
1909 case X86::BI__builtin_ia32_extracti64x2_512_mask: {
1910 mlir::Location loc = getLoc(expr->getExprLoc());
1911 cir::VectorType dstTy = cast<cir::VectorType>(convertType(expr->getType()));
1912 unsigned numElts = dstTy.getSize();
1913 unsigned srcNumElts = cast<cir::VectorType>(ops[0].getType()).getSize();
1914 unsigned subVectors = srcNumElts / numElts;
1915 assert(llvm::isPowerOf2_32(subVectors) && "Expected power of 2 subvectors");
1916 unsigned index =
1917 ops[1].getDefiningOp<cir::ConstantOp>().getIntValue().getZExtValue();
1918
1919 index &= subVectors - 1; // Remove any extra bits.
1920 index *= numElts;
1921
1922 int64_t indices[16];
1923 std::iota(indices, indices + numElts, index);
1924
1925 mlir::Value poison =
1926 builder.getConstant(loc, cir::PoisonAttr::get(ops[0].getType()));
1927 mlir::Value res = builder.createVecShuffle(loc, ops[0], poison,
1928 ArrayRef(indices, numElts));
1929 if (ops.size() == 4)
1930 res = emitX86Select(builder, loc, ops[3], res, ops[2]);
1931
1932 return res;
1933 }
1934 case X86::BI__builtin_ia32_vinsertf128_pd256:
1935 case X86::BI__builtin_ia32_vinsertf128_ps256:
1936 case X86::BI__builtin_ia32_vinsertf128_si256:
1937 case X86::BI__builtin_ia32_insert128i256:
1938 case X86::BI__builtin_ia32_insertf64x4:
1939 case X86::BI__builtin_ia32_insertf32x4:
1940 case X86::BI__builtin_ia32_inserti64x4:
1941 case X86::BI__builtin_ia32_inserti32x4:
1942 case X86::BI__builtin_ia32_insertf32x8:
1943 case X86::BI__builtin_ia32_inserti32x8:
1944 case X86::BI__builtin_ia32_insertf32x4_256:
1945 case X86::BI__builtin_ia32_inserti32x4_256:
1946 case X86::BI__builtin_ia32_insertf64x2_256:
1947 case X86::BI__builtin_ia32_inserti64x2_256:
1948 case X86::BI__builtin_ia32_insertf64x2_512:
1949 case X86::BI__builtin_ia32_inserti64x2_512: {
1950 unsigned dstNumElts = cast<cir::VectorType>(ops[0].getType()).getSize();
1951 unsigned srcNumElts = cast<cir::VectorType>(ops[1].getType()).getSize();
1952 unsigned subVectors = dstNumElts / srcNumElts;
1953 assert(llvm::isPowerOf2_32(subVectors) && "Expected power of 2 subvectors");
1954 assert(dstNumElts <= 16);
1955
1956 uint64_t index = getZExtIntValueFromConstOp(ops[2]);
1957 index &= subVectors - 1; // Remove any extra bits.
1958 index *= srcNumElts;
1959
1960 llvm::SmallVector<int64_t, 16> mask(dstNumElts);
1961 for (unsigned i = 0; i != dstNumElts; ++i)
1962 mask[i] = (i >= srcNumElts) ? srcNumElts + (i % srcNumElts) : i;
1963
1964 mlir::Value op1 =
1965 builder.createVecShuffle(getLoc(expr->getExprLoc()), ops[1], mask);
1966
1967 for (unsigned i = 0; i != dstNumElts; ++i) {
1968 if (i >= index && i < (index + srcNumElts))
1969 mask[i] = (i - index) + dstNumElts;
1970 else
1971 mask[i] = i;
1972 }
1973
1974 return builder.createVecShuffle(getLoc(expr->getExprLoc()), ops[0], op1,
1975 mask);
1976 }
1977 case X86::BI__builtin_ia32_pmovqd512_mask:
1978 case X86::BI__builtin_ia32_pmovwb512_mask: {
1979 mlir::Value Res =
1980 builder.createIntCast(ops[0], cast<cir::VectorType>(ops[1].getType()));
1981 return emitX86Select(builder, getLoc(expr->getExprLoc()), ops[2], Res,
1982 ops[1]);
1983 }
1984 case X86::BI__builtin_ia32_pblendw128:
1985 case X86::BI__builtin_ia32_blendpd:
1986 case X86::BI__builtin_ia32_blendps:
1987 case X86::BI__builtin_ia32_blendpd256:
1988 case X86::BI__builtin_ia32_blendps256:
1989 case X86::BI__builtin_ia32_pblendw256:
1990 case X86::BI__builtin_ia32_pblendd128:
1991 case X86::BI__builtin_ia32_pblendd256: {
1992 uint32_t imm = getZExtIntValueFromConstOp(ops[2]);
1993 unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize();
1994
1996 // If there are more than 8 elements, the immediate is used twice so make
1997 // sure we handle that.
1998 mlir::Type i32Ty = builder.getSInt32Ty();
1999 for (unsigned i = 0; i != numElts; ++i)
2000 indices.push_back(
2001 cir::IntAttr::get(i32Ty, ((imm >> (i % 8)) & 0x1) ? numElts + i : i));
2002
2003 return builder.createVecShuffle(getLoc(expr->getExprLoc()), ops[0], ops[1],
2004 indices);
2005 }
2006 case X86::BI__builtin_ia32_pshuflw:
2007 case X86::BI__builtin_ia32_pshuflw256:
2008 case X86::BI__builtin_ia32_pshuflw512:
2009 return emitPshufWord(builder, ops[0], ops[1], getLoc(expr->getExprLoc()),
2010 true);
2011 case X86::BI__builtin_ia32_pshufhw:
2012 case X86::BI__builtin_ia32_pshufhw256:
2013 case X86::BI__builtin_ia32_pshufhw512:
2014 return emitPshufWord(builder, ops[0], ops[1], getLoc(expr->getExprLoc()),
2015 false);
2016 case X86::BI__builtin_ia32_pshufd:
2017 case X86::BI__builtin_ia32_pshufd256:
2018 case X86::BI__builtin_ia32_pshufd512:
2019 case X86::BI__builtin_ia32_vpermilpd:
2020 case X86::BI__builtin_ia32_vpermilps:
2021 case X86::BI__builtin_ia32_vpermilpd256:
2022 case X86::BI__builtin_ia32_vpermilps256:
2023 case X86::BI__builtin_ia32_vpermilpd512:
2024 case X86::BI__builtin_ia32_vpermilps512: {
2025 const uint32_t imm = getSExtIntValueFromConstOp(ops[1]);
2026
2028 computeFullLaneShuffleMask(*this, ops[0], imm, false, mask);
2029
2030 return builder.createVecShuffle(getLoc(expr->getExprLoc()), ops[0], mask);
2031 }
2032 case X86::BI__builtin_ia32_shufpd:
2033 case X86::BI__builtin_ia32_shufpd256:
2034 case X86::BI__builtin_ia32_shufpd512:
2035 case X86::BI__builtin_ia32_shufps:
2036 case X86::BI__builtin_ia32_shufps256:
2037 case X86::BI__builtin_ia32_shufps512: {
2038 const uint32_t imm = getZExtIntValueFromConstOp(ops[2]);
2039
2041 computeFullLaneShuffleMask(*this, ops[0], imm, true, mask);
2042
2043 return builder.createVecShuffle(getLoc(expr->getExprLoc()), ops[0], ops[1],
2044 mask);
2045 }
2046 case X86::BI__builtin_ia32_permdi256:
2047 case X86::BI__builtin_ia32_permdf256:
2048 case X86::BI__builtin_ia32_permdi512:
2049 case X86::BI__builtin_ia32_permdf512: {
2050 unsigned imm =
2051 ops[1].getDefiningOp<cir::ConstantOp>().getIntValue().getZExtValue();
2052 unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize();
2053
2054 // These intrinsics operate on 256-bit lanes of four 64-bit elements.
2055 int64_t Indices[8];
2056
2057 for (unsigned l = 0; l != numElts; l += 4)
2058 for (unsigned i = 0; i != 4; ++i)
2059 Indices[l + i] = l + ((imm >> (2 * i)) & 0x3);
2060
2061 return builder.createVecShuffle(getLoc(expr->getExprLoc()), ops[0],
2062 ArrayRef(Indices, numElts));
2063 }
2064 case X86::BI__builtin_ia32_palignr128:
2065 case X86::BI__builtin_ia32_palignr256:
2066 case X86::BI__builtin_ia32_palignr512: {
2067 uint32_t shiftVal = getZExtIntValueFromConstOp(ops[2]) & 0xff;
2068
2069 unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize();
2070 assert(numElts % 16 == 0);
2071
2072 // If palignr is shifting the pair of vectors more than the size of two
2073 // lanes, emit zero.
2074 if (shiftVal >= 32)
2075 return builder.getNullValue(convertType(expr->getType()),
2076 getLoc(expr->getExprLoc()));
2077
2078 // If palignr is shifting the pair of input vectors more than one lane,
2079 // but less than two lanes, convert to shifting in zeroes.
2080 if (shiftVal > 16) {
2081 shiftVal -= 16;
2082 ops[1] = ops[0];
2083 ops[0] =
2084 builder.getNullValue(ops[0].getType(), getLoc(expr->getExprLoc()));
2085 }
2086
2087 int64_t indices[64];
2088 // 256-bit palignr operates on 128-bit lanes so we need to handle that
2089 for (unsigned l = 0; l != numElts; l += 16) {
2090 for (unsigned i = 0; i != 16; ++i) {
2091 uint32_t idx = shiftVal + i;
2092 if (idx >= 16)
2093 idx += numElts - 16; // End of lane, switch operand.
2094 indices[l + i] = l + idx;
2095 }
2096 }
2097
2098 return builder.createVecShuffle(getLoc(expr->getExprLoc()), ops[1], ops[0],
2099 ArrayRef(indices, numElts));
2100 }
2101 case X86::BI__builtin_ia32_alignd128:
2102 case X86::BI__builtin_ia32_alignd256:
2103 case X86::BI__builtin_ia32_alignd512:
2104 case X86::BI__builtin_ia32_alignq128:
2105 case X86::BI__builtin_ia32_alignq256:
2106 case X86::BI__builtin_ia32_alignq512: {
2107 unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize();
2108 unsigned shiftVal =
2109 ops[2].getDefiningOp<cir::ConstantOp>().getIntValue().getZExtValue() &
2110 0xff;
2111
2112 // Mask the shift amount to width of a vector.
2113 shiftVal &= numElts - 1;
2114
2116 mlir::Type i32Ty = builder.getSInt32Ty();
2117 for (unsigned i = 0; i != numElts; ++i)
2118 indices.push_back(cir::IntAttr::get(i32Ty, i + shiftVal));
2119
2120 return builder.createVecShuffle(getLoc(expr->getExprLoc()), ops[0], ops[1],
2121 indices);
2122 }
2123 case X86::BI__builtin_ia32_shuf_f32x4_256:
2124 case X86::BI__builtin_ia32_shuf_f64x2_256:
2125 case X86::BI__builtin_ia32_shuf_i32x4_256:
2126 case X86::BI__builtin_ia32_shuf_i64x2_256:
2127 case X86::BI__builtin_ia32_shuf_f32x4:
2128 case X86::BI__builtin_ia32_shuf_f64x2:
2129 case X86::BI__builtin_ia32_shuf_i32x4:
2130 case X86::BI__builtin_ia32_shuf_i64x2: {
2131 mlir::Value src1 = ops[0];
2132 mlir::Value src2 = ops[1];
2133
2134 unsigned imm =
2135 ops[2].getDefiningOp<cir::ConstantOp>().getIntValue().getZExtValue();
2136
2137 unsigned numElems = cast<cir::VectorType>(src1.getType()).getSize();
2138 unsigned totalBits = getContext().getTypeSize(expr->getArg(0)->getType());
2139 unsigned numLanes = totalBits == 512 ? 4 : 2;
2140 unsigned numElemsPerLane = numElems / numLanes;
2141
2143 mlir::Type i32Ty = builder.getSInt32Ty();
2144
2145 for (unsigned l = 0; l != numElems; l += numElemsPerLane) {
2146 unsigned index = (imm % numLanes) * numElemsPerLane;
2147 imm /= numLanes;
2148 if (l >= (numElems / 2))
2149 index += numElems;
2150 for (unsigned i = 0; i != numElemsPerLane; ++i) {
2151 indices.push_back(cir::IntAttr::get(i32Ty, index + i));
2152 }
2153 }
2154
2155 return builder.createVecShuffle(getLoc(expr->getExprLoc()), src1, src2,
2156 indices);
2157 }
2158 case X86::BI__builtin_ia32_vperm2f128_pd256:
2159 case X86::BI__builtin_ia32_vperm2f128_ps256:
2160 case X86::BI__builtin_ia32_vperm2f128_si256:
2161 case X86::BI__builtin_ia32_permti256:
2162 return emitX86VPerm2f128(builder, getLoc(expr->getExprLoc()), ops);
2163 case X86::BI__builtin_ia32_pslldqi128_byteshift:
2164 case X86::BI__builtin_ia32_pslldqi256_byteshift:
2165 case X86::BI__builtin_ia32_pslldqi512_byteshift:
2166 return emitX86PackedByteShift(builder, builtinID,
2167 getLoc(expr->getExprLoc()), ops,
2168 /**isLeftShift=*/true);
2169 case X86::BI__builtin_ia32_psrldqi128_byteshift:
2170 case X86::BI__builtin_ia32_psrldqi256_byteshift:
2171 case X86::BI__builtin_ia32_psrldqi512_byteshift:
2172 return emitX86PackedByteShift(builder, builtinID,
2173 getLoc(expr->getExprLoc()), ops,
2174 /**isLeftShift=*/false);
2175 case X86::BI__builtin_ia32_kshiftliqi:
2176 case X86::BI__builtin_ia32_kshiftlihi:
2177 case X86::BI__builtin_ia32_kshiftlisi:
2178 case X86::BI__builtin_ia32_kshiftlidi: {
2179 mlir::Location loc = getLoc(expr->getExprLoc());
2180 unsigned shiftVal =
2181 ops[1].getDefiningOp<cir::ConstantOp>().getIntValue().getZExtValue() &
2182 0xff;
2183 unsigned numElems = cast<cir::IntType>(ops[0].getType()).getWidth();
2184
2185 if (shiftVal >= numElems)
2186 return builder.getNullValue(ops[0].getType(), loc);
2187
2188 mlir::Value in = getMaskVecValue(builder, loc, ops[0], numElems);
2189
2191 mlir::Type i32Ty = builder.getSInt32Ty();
2192 for (auto i : llvm::seq<unsigned>(0, numElems))
2193 indices.push_back(cir::IntAttr::get(i32Ty, numElems + i - shiftVal));
2194
2195 mlir::Value zero = builder.getNullValue(in.getType(), loc);
2196 mlir::Value sv = builder.createVecShuffle(loc, zero, in, indices);
2197 return builder.createBitcast(sv, ops[0].getType());
2198 }
2199 case X86::BI__builtin_ia32_kshiftriqi:
2200 case X86::BI__builtin_ia32_kshiftrihi:
2201 case X86::BI__builtin_ia32_kshiftrisi:
2202 case X86::BI__builtin_ia32_kshiftridi: {
2203 mlir::Location loc = getLoc(expr->getExprLoc());
2204 unsigned shiftVal =
2205 ops[1].getDefiningOp<cir::ConstantOp>().getIntValue().getZExtValue() &
2206 0xff;
2207 unsigned numElems = cast<cir::IntType>(ops[0].getType()).getWidth();
2208
2209 if (shiftVal >= numElems)
2210 return builder.getNullValue(ops[0].getType(), loc);
2211
2212 mlir::Value in = getMaskVecValue(builder, loc, ops[0], numElems);
2213
2215 mlir::Type i32Ty = builder.getSInt32Ty();
2216 for (auto i : llvm::seq<unsigned>(0, numElems))
2217 indices.push_back(cir::IntAttr::get(i32Ty, i + shiftVal));
2218
2219 mlir::Value zero = builder.getNullValue(in.getType(), loc);
2220 mlir::Value sv = builder.createVecShuffle(loc, in, zero, indices);
2221 return builder.createBitcast(sv, ops[0].getType());
2222 }
2223 case X86::BI__builtin_ia32_movnti:
2224 case X86::BI__builtin_ia32_movnti64:
2225 case X86::BI__builtin_ia32_movntsd:
2226 case X86::BI__builtin_ia32_movntss: {
2227 mlir::Location loc = getLoc(expr->getExprLoc());
2228
2229 Address dest = Address{ops[0], CharUnits::One()};
2230 mlir::Value src = ops[1];
2231
2232 if (builtinID == X86::BI__builtin_ia32_movntsd ||
2233 builtinID == X86::BI__builtin_ia32_movntss)
2234 src = builder.createExtractElement(loc, ops[1], 0);
2235
2236 cir::StoreOp so =
2237 builder.createStore(loc, src, dest,
2238 /*isVolatile=*/false, /*isNontemporal=*/true);
2239 return so.getValue();
2240 }
2241 case X86::BI__builtin_ia32_vprotbi:
2242 case X86::BI__builtin_ia32_vprotwi:
2243 case X86::BI__builtin_ia32_vprotdi:
2244 case X86::BI__builtin_ia32_vprotqi:
2245 case X86::BI__builtin_ia32_prold128:
2246 case X86::BI__builtin_ia32_prold256:
2247 case X86::BI__builtin_ia32_prold512:
2248 case X86::BI__builtin_ia32_prolq128:
2249 case X86::BI__builtin_ia32_prolq256:
2250 case X86::BI__builtin_ia32_prolq512:
2251 return emitX86FunnelShift(builder, getLoc(expr->getExprLoc()), ops[0],
2252 ops[0], ops[1], false);
2253 case X86::BI__builtin_ia32_prord128:
2254 case X86::BI__builtin_ia32_prord256:
2255 case X86::BI__builtin_ia32_prord512:
2256 case X86::BI__builtin_ia32_prorq128:
2257 case X86::BI__builtin_ia32_prorq256:
2258 case X86::BI__builtin_ia32_prorq512:
2259 return emitX86FunnelShift(builder, getLoc(expr->getExprLoc()), ops[0],
2260 ops[0], ops[1], true);
2261 case X86::BI__builtin_ia32_selectb_128:
2262 case X86::BI__builtin_ia32_selectb_256:
2263 case X86::BI__builtin_ia32_selectb_512:
2264 case X86::BI__builtin_ia32_selectw_128:
2265 case X86::BI__builtin_ia32_selectw_256:
2266 case X86::BI__builtin_ia32_selectw_512:
2267 case X86::BI__builtin_ia32_selectd_128:
2268 case X86::BI__builtin_ia32_selectd_256:
2269 case X86::BI__builtin_ia32_selectd_512:
2270 case X86::BI__builtin_ia32_selectq_128:
2271 case X86::BI__builtin_ia32_selectq_256:
2272 case X86::BI__builtin_ia32_selectq_512:
2273 case X86::BI__builtin_ia32_selectph_128:
2274 case X86::BI__builtin_ia32_selectph_256:
2275 case X86::BI__builtin_ia32_selectph_512:
2276 case X86::BI__builtin_ia32_selectpbf_128:
2277 case X86::BI__builtin_ia32_selectpbf_256:
2278 case X86::BI__builtin_ia32_selectpbf_512:
2279 case X86::BI__builtin_ia32_selectps_128:
2280 case X86::BI__builtin_ia32_selectps_256:
2281 case X86::BI__builtin_ia32_selectps_512:
2282 case X86::BI__builtin_ia32_selectpd_128:
2283 case X86::BI__builtin_ia32_selectpd_256:
2284 case X86::BI__builtin_ia32_selectpd_512:
2285 return emitX86Select(builder, getLoc(expr->getExprLoc()), ops[0], ops[1],
2286 ops[2]);
2287 case X86::BI__builtin_ia32_selectsh_128:
2288 case X86::BI__builtin_ia32_selectsbf_128:
2289 case X86::BI__builtin_ia32_selectss_128:
2290 case X86::BI__builtin_ia32_selectsd_128: {
2291 mlir::Location loc = getLoc(expr->getExprLoc());
2292 mlir::Value scalar1 =
2293 builder.createExtractElement(loc, ops[1], uint64_t(0));
2294 mlir::Value scalar2 =
2295 builder.createExtractElement(loc, ops[2], uint64_t(0));
2296 mlir::Value result =
2297 emitX86ScalarSelect(builder, loc, ops[0], scalar1, scalar2);
2298 return builder.createInsertElement(loc, ops[1], result, uint64_t(0));
2299 }
2300 case X86::BI__builtin_ia32_cmpb128_mask:
2301 case X86::BI__builtin_ia32_cmpb256_mask:
2302 case X86::BI__builtin_ia32_cmpb512_mask:
2303 case X86::BI__builtin_ia32_cmpw128_mask:
2304 case X86::BI__builtin_ia32_cmpw256_mask:
2305 case X86::BI__builtin_ia32_cmpw512_mask:
2306 case X86::BI__builtin_ia32_cmpd128_mask:
2307 case X86::BI__builtin_ia32_cmpd256_mask:
2308 case X86::BI__builtin_ia32_cmpd512_mask:
2309 case X86::BI__builtin_ia32_cmpq128_mask:
2310 case X86::BI__builtin_ia32_cmpq256_mask:
2311 case X86::BI__builtin_ia32_cmpq512_mask:
2312 case X86::BI__builtin_ia32_ucmpb128_mask:
2313 case X86::BI__builtin_ia32_ucmpb256_mask:
2314 case X86::BI__builtin_ia32_ucmpb512_mask:
2315 case X86::BI__builtin_ia32_ucmpw128_mask:
2316 case X86::BI__builtin_ia32_ucmpw256_mask:
2317 case X86::BI__builtin_ia32_ucmpw512_mask:
2318 case X86::BI__builtin_ia32_ucmpd128_mask:
2319 case X86::BI__builtin_ia32_ucmpd256_mask:
2320 case X86::BI__builtin_ia32_ucmpd512_mask:
2321 case X86::BI__builtin_ia32_ucmpq128_mask:
2322 case X86::BI__builtin_ia32_ucmpq256_mask:
2323 case X86::BI__builtin_ia32_ucmpq512_mask: {
2324 int64_t cc = CIRGenFunction::getZExtIntValueFromConstOp(ops[2]) & 0x7;
2325 return emitX86MaskedCompare(builder, cc, 1, ops,
2326 getLoc(expr->getExprLoc()));
2327 }
2328 case X86::BI__builtin_ia32_vpcomb:
2329 case X86::BI__builtin_ia32_vpcomw:
2330 case X86::BI__builtin_ia32_vpcomd:
2331 case X86::BI__builtin_ia32_vpcomq:
2332 return emitX86vpcom(builder, getLoc(expr->getExprLoc()), ops, true);
2333 case X86::BI__builtin_ia32_vpcomub:
2334 case X86::BI__builtin_ia32_vpcomuw:
2335 case X86::BI__builtin_ia32_vpcomud:
2336 case X86::BI__builtin_ia32_vpcomuq:
2337 return emitX86vpcom(builder, getLoc(expr->getExprLoc()), ops, false);
2338 case X86::BI__builtin_ia32_kortestcqi:
2339 case X86::BI__builtin_ia32_kortestchi:
2340 case X86::BI__builtin_ia32_kortestcsi:
2341 case X86::BI__builtin_ia32_kortestcdi: {
2342 mlir::Location loc = getLoc(expr->getExprLoc());
2343 cir::IntType ty = cast<cir::IntType>(ops[0].getType());
2344 mlir::Value allOnesOp =
2345 builder.getConstAPInt(loc, ty, APInt::getAllOnes(ty.getWidth()));
2346 mlir::Value orOp = emitX86MaskLogic<cir::OrOp>(builder, loc, ops);
2347 mlir::Value cmp =
2348 cir::CmpOp::create(builder, loc, cir::CmpOpKind::eq, orOp, allOnesOp);
2349 return builder.createCast(cir::CastKind::bool_to_int, cmp,
2350 cgm.convertType(expr->getType()));
2351 }
2352 case X86::BI__builtin_ia32_kortestzqi:
2353 case X86::BI__builtin_ia32_kortestzhi:
2354 case X86::BI__builtin_ia32_kortestzsi:
2355 case X86::BI__builtin_ia32_kortestzdi: {
2356 mlir::Location loc = getLoc(expr->getExprLoc());
2357 cir::IntType ty = cast<cir::IntType>(ops[0].getType());
2358 mlir::Value allZerosOp = builder.getNullValue(ty, loc).getResult();
2359 mlir::Value orOp = emitX86MaskLogic<cir::OrOp>(builder, loc, ops);
2360 mlir::Value cmp =
2361 cir::CmpOp::create(builder, loc, cir::CmpOpKind::eq, orOp, allZerosOp);
2362 return builder.createCast(cir::CastKind::bool_to_int, cmp,
2363 cgm.convertType(expr->getType()));
2364 }
2365 case X86::BI__builtin_ia32_ktestcqi:
2366 return emitX86MaskTest(builder, getLoc(expr->getExprLoc()),
2367 "x86.avx512.ktestc.b", ops);
2368 case X86::BI__builtin_ia32_ktestzqi:
2369 return emitX86MaskTest(builder, getLoc(expr->getExprLoc()),
2370 "x86.avx512.ktestz.b", ops);
2371 case X86::BI__builtin_ia32_ktestchi:
2372 return emitX86MaskTest(builder, getLoc(expr->getExprLoc()),
2373 "x86.avx512.ktestc.w", ops);
2374 case X86::BI__builtin_ia32_ktestzhi:
2375 return emitX86MaskTest(builder, getLoc(expr->getExprLoc()),
2376 "x86.avx512.ktestz.w", ops);
2377 case X86::BI__builtin_ia32_ktestcsi:
2378 return emitX86MaskTest(builder, getLoc(expr->getExprLoc()),
2379 "x86.avx512.ktestc.d", ops);
2380 case X86::BI__builtin_ia32_ktestzsi:
2381 return emitX86MaskTest(builder, getLoc(expr->getExprLoc()),
2382 "x86.avx512.ktestz.d", ops);
2383 case X86::BI__builtin_ia32_ktestcdi:
2384 return emitX86MaskTest(builder, getLoc(expr->getExprLoc()),
2385 "x86.avx512.ktestc.q", ops);
2386 case X86::BI__builtin_ia32_ktestzdi:
2387 return emitX86MaskTest(builder, getLoc(expr->getExprLoc()),
2388 "x86.avx512.ktestz.q", ops);
2389 case X86::BI__builtin_ia32_kaddqi:
2390 return emitX86MaskAddLogic(builder, getLoc(expr->getExprLoc()),
2391 "x86.avx512.kadd.b", ops);
2392 case X86::BI__builtin_ia32_kaddhi:
2393 return emitX86MaskAddLogic(builder, getLoc(expr->getExprLoc()),
2394 "x86.avx512.kadd.w", ops);
2395 case X86::BI__builtin_ia32_kaddsi:
2396 return emitX86MaskAddLogic(builder, getLoc(expr->getExprLoc()),
2397 "x86.avx512.kadd.d", ops);
2398 case X86::BI__builtin_ia32_kadddi:
2399 return emitX86MaskAddLogic(builder, getLoc(expr->getExprLoc()),
2400 "x86.avx512.kadd.q", ops);
2401 case X86::BI__builtin_ia32_kandqi:
2402 case X86::BI__builtin_ia32_kandhi:
2403 case X86::BI__builtin_ia32_kandsi:
2404 case X86::BI__builtin_ia32_kanddi:
2405 return emitX86MaskLogic<cir::AndOp>(builder, getLoc(expr->getExprLoc()),
2406 ops);
2407 case X86::BI__builtin_ia32_kandnqi:
2408 case X86::BI__builtin_ia32_kandnhi:
2409 case X86::BI__builtin_ia32_kandnsi:
2410 case X86::BI__builtin_ia32_kandndi:
2411 return emitX86MaskLogic<cir::AndOp>(builder, getLoc(expr->getExprLoc()),
2412 ops, /*invertLHS=*/true);
2413 case X86::BI__builtin_ia32_korqi:
2414 case X86::BI__builtin_ia32_korhi:
2415 case X86::BI__builtin_ia32_korsi:
2416 case X86::BI__builtin_ia32_kordi:
2417 return emitX86MaskLogic<cir::OrOp>(builder, getLoc(expr->getExprLoc()),
2418 ops);
2419 case X86::BI__builtin_ia32_kxnorqi:
2420 case X86::BI__builtin_ia32_kxnorhi:
2421 case X86::BI__builtin_ia32_kxnorsi:
2422 case X86::BI__builtin_ia32_kxnordi:
2423 return emitX86MaskLogic<cir::XorOp>(builder, getLoc(expr->getExprLoc()),
2424 ops, /*invertLHS=*/true);
2425 case X86::BI__builtin_ia32_kxorqi:
2426 case X86::BI__builtin_ia32_kxorhi:
2427 case X86::BI__builtin_ia32_kxorsi:
2428 case X86::BI__builtin_ia32_kxordi:
2429 return emitX86MaskLogic<cir::XorOp>(builder, getLoc(expr->getExprLoc()),
2430 ops);
2431 case X86::BI__builtin_ia32_knotqi:
2432 case X86::BI__builtin_ia32_knothi:
2433 case X86::BI__builtin_ia32_knotsi:
2434 case X86::BI__builtin_ia32_knotdi: {
2435 cir::IntType intTy = cast<cir::IntType>(ops[0].getType());
2436 unsigned numElts = intTy.getWidth();
2437 mlir::Value resVec =
2438 getMaskVecValue(builder, getLoc(expr->getExprLoc()), ops[0], numElts);
2439 return builder.createBitcast(builder.createNot(resVec), ops[0].getType());
2440 }
2441 case X86::BI__builtin_ia32_kmovb:
2442 case X86::BI__builtin_ia32_kmovw:
2443 case X86::BI__builtin_ia32_kmovd:
2444 case X86::BI__builtin_ia32_kmovq: {
2445 // Bitcast to vXi1 type and then back to integer. This gets the mask
2446 // register type into the IR, but might be optimized out depending on
2447 // what's around it.
2448 cir::IntType intTy = cast<cir::IntType>(ops[0].getType());
2449 unsigned numElts = intTy.getWidth();
2450 mlir::Value resVec =
2451 getMaskVecValue(builder, getLoc(expr->getExprLoc()), ops[0], numElts);
2452 return builder.createBitcast(resVec, ops[0].getType());
2453 }
2454 case X86::BI__builtin_ia32_sqrtsh_round_mask:
2455 case X86::BI__builtin_ia32_sqrtsd_round_mask:
2456 case X86::BI__builtin_ia32_sqrtss_round_mask:
2457 cgm.errorNYI(expr->getSourceRange(),
2458 std::string("unimplemented X86 builtin call: ") +
2459 getContext().BuiltinInfo.getName(builtinID));
2460 return mlir::Value{};
2461 case X86::BI__builtin_ia32_sqrtph512:
2462 case X86::BI__builtin_ia32_sqrtps512:
2463 case X86::BI__builtin_ia32_sqrtpd512: {
2464 mlir::Location loc = getLoc(expr->getExprLoc());
2465 mlir::Value arg = ops[0];
2466 return cir::SqrtOp::create(builder, loc, arg).getResult();
2467 }
2468 case X86::BI__builtin_ia32_pmulhw128:
2469 case X86::BI__builtin_ia32_pmulhw256:
2470 case X86::BI__builtin_ia32_pmulhw512:
2471 return builder.emitIntrinsicCallOp(getLoc(expr->getExprLoc()), "smulh",
2472 ops[0].getType(), ops);
2473 case X86::BI__builtin_ia32_pmulhuw128:
2474 case X86::BI__builtin_ia32_pmulhuw256:
2475 case X86::BI__builtin_ia32_pmulhuw512:
2476 return builder.emitIntrinsicCallOp(getLoc(expr->getExprLoc()), "umulh",
2477 ops[0].getType(), ops);
2478 case X86::BI__builtin_ia32_pmuludq128:
2479 case X86::BI__builtin_ia32_pmuludq256:
2480 case X86::BI__builtin_ia32_pmuludq512: {
2481 unsigned opTypePrimitiveSizeInBits =
2482 cgm.getDataLayout().getTypeSizeInBits(ops[0].getType());
2483 return emitX86Muldq(builder, getLoc(expr->getExprLoc()), /*isSigned*/ false,
2484 ops, opTypePrimitiveSizeInBits);
2485 }
2486 case X86::BI__builtin_ia32_pmuldq128:
2487 case X86::BI__builtin_ia32_pmuldq256:
2488 case X86::BI__builtin_ia32_pmuldq512: {
2489 unsigned opTypePrimitiveSizeInBits =
2490 cgm.getDataLayout().getTypeSizeInBits(ops[0].getType());
2491 return emitX86Muldq(builder, getLoc(expr->getExprLoc()), /*isSigned*/ true,
2492 ops, opTypePrimitiveSizeInBits);
2493 }
2494 case X86::BI__builtin_ia32_pternlogd512_mask:
2495 case X86::BI__builtin_ia32_pternlogq512_mask:
2496 case X86::BI__builtin_ia32_pternlogd128_mask:
2497 case X86::BI__builtin_ia32_pternlogd256_mask:
2498 case X86::BI__builtin_ia32_pternlogq128_mask:
2499 case X86::BI__builtin_ia32_pternlogq256_mask:
2500 case X86::BI__builtin_ia32_pternlogd512_maskz:
2501 case X86::BI__builtin_ia32_pternlogq512_maskz:
2502 case X86::BI__builtin_ia32_pternlogd128_maskz:
2503 case X86::BI__builtin_ia32_pternlogd256_maskz:
2504 case X86::BI__builtin_ia32_pternlogq128_maskz:
2505 case X86::BI__builtin_ia32_pternlogq256_maskz:
2506 cgm.errorNYI(expr->getSourceRange(),
2507 std::string("unimplemented X86 builtin call: ") +
2508 getContext().BuiltinInfo.getName(builtinID));
2509 return mlir::Value{};
2510 case X86::BI__builtin_ia32_vpshldd128:
2511 case X86::BI__builtin_ia32_vpshldd256:
2512 case X86::BI__builtin_ia32_vpshldd512:
2513 case X86::BI__builtin_ia32_vpshldq128:
2514 case X86::BI__builtin_ia32_vpshldq256:
2515 case X86::BI__builtin_ia32_vpshldq512:
2516 case X86::BI__builtin_ia32_vpshldw128:
2517 case X86::BI__builtin_ia32_vpshldw256:
2518 case X86::BI__builtin_ia32_vpshldw512:
2519 return emitX86FunnelShift(builder, getLoc(expr->getExprLoc()), ops[0],
2520 ops[1], ops[2], false);
2521 case X86::BI__builtin_ia32_vpshrdd128:
2522 case X86::BI__builtin_ia32_vpshrdd256:
2523 case X86::BI__builtin_ia32_vpshrdd512:
2524 case X86::BI__builtin_ia32_vpshrdq128:
2525 case X86::BI__builtin_ia32_vpshrdq256:
2526 case X86::BI__builtin_ia32_vpshrdq512:
2527 case X86::BI__builtin_ia32_vpshrdw128:
2528 case X86::BI__builtin_ia32_vpshrdw256:
2529 case X86::BI__builtin_ia32_vpshrdw512:
2530 // Ops 0 and 1 are swapped.
2531 return emitX86FunnelShift(builder, getLoc(expr->getExprLoc()), ops[1],
2532 ops[0], ops[2], true);
2533 case X86::BI__builtin_ia32_reduce_fadd_pd512:
2534 case X86::BI__builtin_ia32_reduce_fadd_ps512:
2535 case X86::BI__builtin_ia32_reduce_fadd_ph512:
2536 case X86::BI__builtin_ia32_reduce_fadd_ph256:
2537 case X86::BI__builtin_ia32_reduce_fadd_ph128: {
2538 CIRGenFPOptionsRAII FPOptsRAII(*this, expr);
2539 cir::FastMathFlags fastMathFlags = getCurrentFastMathFlags();
2540 fastMathFlags |= cir::FastMathFlags::reassoc;
2541 cir::FastMathFlagsAttr fastMath = getFastMathFlagsAttr(fastMathFlags);
2542 return cir::VecReduceFAddOp::create(builder, getLoc(expr->getExprLoc()),
2543 ops[0], ops[1], fastMath)
2544 .getResult();
2545 }
2546 case X86::BI__builtin_ia32_reduce_fmul_pd512:
2547 case X86::BI__builtin_ia32_reduce_fmul_ps512:
2548 case X86::BI__builtin_ia32_reduce_fmul_ph512:
2549 case X86::BI__builtin_ia32_reduce_fmul_ph256:
2550 case X86::BI__builtin_ia32_reduce_fmul_ph128: {
2551 CIRGenFPOptionsRAII FPOptsRAII(*this, expr);
2552 cir::FastMathFlags fastMathFlags = getCurrentFastMathFlags();
2553 fastMathFlags |= cir::FastMathFlags::reassoc;
2554 cir::FastMathFlagsAttr fastMath = getFastMathFlagsAttr(fastMathFlags);
2555 return cir::VecReduceFMulOp::create(builder, getLoc(expr->getExprLoc()),
2556 ops[0], ops[1], fastMath)
2557 .getResult();
2558 }
2559 case X86::BI__builtin_ia32_reduce_fmax_pd512:
2560 case X86::BI__builtin_ia32_reduce_fmax_ps512:
2561 case X86::BI__builtin_ia32_reduce_fmax_ph512:
2562 case X86::BI__builtin_ia32_reduce_fmax_ph256:
2563 case X86::BI__builtin_ia32_reduce_fmax_ph128: {
2564 CIRGenFPOptionsRAII FPOptsRAII(*this, expr);
2565 cir::FastMathFlags fastMathFlags = getCurrentFastMathFlags();
2566 fastMathFlags |= cir::FastMathFlags::nnan;
2567 cir::FastMathFlagsAttr fastMath = getFastMathFlagsAttr(fastMathFlags);
2568 return cir::VecReduceFMaxOp::create(builder, getLoc(expr->getExprLoc()),
2569 ops[0], fastMath)
2570 .getResult();
2571 }
2572 case X86::BI__builtin_ia32_reduce_fmin_pd512:
2573 case X86::BI__builtin_ia32_reduce_fmin_ps512:
2574 case X86::BI__builtin_ia32_reduce_fmin_ph512:
2575 case X86::BI__builtin_ia32_reduce_fmin_ph256:
2576 case X86::BI__builtin_ia32_reduce_fmin_ph128: {
2577 CIRGenFPOptionsRAII FPOptsRAII(*this, expr);
2578 cir::FastMathFlags fastMathFlags = getCurrentFastMathFlags();
2579 fastMathFlags |= cir::FastMathFlags::nnan;
2580 cir::FastMathFlagsAttr fastMath = getFastMathFlagsAttr(fastMathFlags);
2581 return cir::VecReduceFMinOp::create(builder, getLoc(expr->getExprLoc()),
2582 ops[0], fastMath)
2583 .getResult();
2584 }
2585 case X86::BI__builtin_ia32_rdrand16_step:
2586 case X86::BI__builtin_ia32_rdrand32_step:
2587 case X86::BI__builtin_ia32_rdrand64_step:
2588 case X86::BI__builtin_ia32_rdseed16_step:
2589 case X86::BI__builtin_ia32_rdseed32_step:
2590 case X86::BI__builtin_ia32_rdseed64_step: {
2591 llvm::StringRef intrinsicName;
2592 switch (builtinID) {
2593 default:
2594 llvm_unreachable("Unsupported intrinsic!");
2595 case X86::BI__builtin_ia32_rdrand16_step:
2596 intrinsicName = "x86.rdrand.16";
2597 break;
2598 case X86::BI__builtin_ia32_rdrand32_step:
2599 intrinsicName = "x86.rdrand.32";
2600 break;
2601 case X86::BI__builtin_ia32_rdrand64_step:
2602 intrinsicName = "x86.rdrand.64";
2603 break;
2604 case X86::BI__builtin_ia32_rdseed16_step:
2605 intrinsicName = "x86.rdseed.16";
2606 break;
2607 case X86::BI__builtin_ia32_rdseed32_step:
2608 intrinsicName = "x86.rdseed.32";
2609 break;
2610 case X86::BI__builtin_ia32_rdseed64_step:
2611 intrinsicName = "x86.rdseed.64";
2612 break;
2613 }
2614
2615 mlir::Location loc = getLoc(expr->getExprLoc());
2616 mlir::Type randTy = cast<cir::PointerType>(ops[0].getType()).getPointee();
2617 llvm::SmallVector<mlir::Type, 2> resultTypes = {randTy,
2618 builder.getUInt32Ty()};
2619 cir::StructType resRecord = cir::StructType::get(
2620 &getMLIRContext(), resultTypes, /*packed=*/false,
2621 /*is_class=*/false, cir::RecordType::getAllDataKinds(resultTypes));
2622
2623 mlir::Value call =
2624 builder.emitIntrinsicCallOp(loc, intrinsicName, resRecord);
2625 mlir::Value rand =
2626 cir::ExtractMemberOp::create(builder, loc, randTy, call, 0);
2627 builder.CIRBaseBuilderTy::createStore(loc, rand, ops[0]);
2628
2629 return cir::ExtractMemberOp::create(builder, loc, builder.getUInt32Ty(),
2630 call, 1);
2631 }
2632 case X86::BI__builtin_ia32_addcarryx_u32:
2633 case X86::BI__builtin_ia32_addcarryx_u64:
2634 case X86::BI__builtin_ia32_subborrow_u32:
2635 case X86::BI__builtin_ia32_subborrow_u64:
2636 cgm.errorNYI(expr->getSourceRange(),
2637 std::string("unimplemented X86 builtin call: ") +
2638 getContext().BuiltinInfo.getName(builtinID));
2639 return mlir::Value{};
2640 case X86::BI__builtin_ia32_fpclassps128_mask:
2641 case X86::BI__builtin_ia32_fpclassps256_mask:
2642 case X86::BI__builtin_ia32_fpclassps512_mask:
2643 case X86::BI__builtin_ia32_vfpclassbf16128_mask:
2644 case X86::BI__builtin_ia32_vfpclassbf16256_mask:
2645 case X86::BI__builtin_ia32_vfpclassbf16512_mask:
2646 case X86::BI__builtin_ia32_fpclassph128_mask:
2647 case X86::BI__builtin_ia32_fpclassph256_mask:
2648 case X86::BI__builtin_ia32_fpclassph512_mask:
2649 case X86::BI__builtin_ia32_fpclasspd128_mask:
2650 case X86::BI__builtin_ia32_fpclasspd256_mask:
2651 case X86::BI__builtin_ia32_fpclasspd512_mask:
2652 return emitX86Fpclass(builder, getLoc(expr->getExprLoc()), builtinID, ops);
2653 case X86::BI__builtin_ia32_vp2intersect_q_512:
2654 case X86::BI__builtin_ia32_vp2intersect_q_256:
2655 case X86::BI__builtin_ia32_vp2intersect_q_128:
2656 case X86::BI__builtin_ia32_vp2intersect_d_512:
2657 case X86::BI__builtin_ia32_vp2intersect_d_256:
2658 case X86::BI__builtin_ia32_vp2intersect_d_128: {
2659 unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize();
2660 mlir::Location loc = getLoc(expr->getExprLoc());
2661 StringRef intrinsicName;
2662
2663 switch (builtinID) {
2664 default:
2665 llvm_unreachable("Unexpected builtin");
2666 case X86::BI__builtin_ia32_vp2intersect_q_512:
2667 intrinsicName = "x86.avx512.vp2intersect.q.512";
2668 break;
2669 case X86::BI__builtin_ia32_vp2intersect_q_256:
2670 intrinsicName = "x86.avx512.vp2intersect.q.256";
2671 break;
2672 case X86::BI__builtin_ia32_vp2intersect_q_128:
2673 intrinsicName = "x86.avx512.vp2intersect.q.128";
2674 break;
2675 case X86::BI__builtin_ia32_vp2intersect_d_512:
2676 intrinsicName = "x86.avx512.vp2intersect.d.512";
2677 break;
2678 case X86::BI__builtin_ia32_vp2intersect_d_256:
2679 intrinsicName = "x86.avx512.vp2intersect.d.256";
2680 break;
2681 case X86::BI__builtin_ia32_vp2intersect_d_128:
2682 intrinsicName = "x86.avx512.vp2intersect.d.128";
2683 break;
2684 }
2685
2686 auto resVector = cir::VectorType::get(builder.getSIntNTy(1), numElts);
2687
2688 mlir::Type resMembers[] = {resVector, resVector};
2689 cir::StructType resRecord = cir::StructType::get(
2690 &getMLIRContext(), resMembers, /*packed=*/false, /*is_class=*/false,
2692
2693 mlir::Value call = builder.emitIntrinsicCallOp(
2694 getLoc(expr->getExprLoc()), intrinsicName, resRecord,
2695 mlir::ValueRange{ops[0], ops[1]});
2696 mlir::Value result =
2697 cir::ExtractMemberOp::create(builder, loc, resVector, call, 0);
2698 result = emitX86MaskedCompareResult(builder, result, numElts, nullptr, loc);
2699 Address addr = Address(
2700 ops[2], clang::CharUnits::fromQuantity(std::max(1U, numElts / 8)));
2701 builder.createStore(loc, result, addr);
2702
2703 result = cir::ExtractMemberOp::create(builder, loc, resVector, call, 1);
2704 result = emitX86MaskedCompareResult(builder, result, numElts, nullptr, loc);
2705 addr = Address(ops[3],
2706 clang::CharUnits::fromQuantity(std::max(1U, numElts / 8)));
2707 builder.createStore(loc, result, addr);
2708 return mlir::Value{};
2709 }
2710 case X86::BI__builtin_ia32_vpmultishiftqb128:
2711 case X86::BI__builtin_ia32_vpmultishiftqb256:
2712 case X86::BI__builtin_ia32_vpmultishiftqb512:
2713 case X86::BI__builtin_ia32_vpshufbitqmb128_mask:
2714 case X86::BI__builtin_ia32_vpshufbitqmb256_mask:
2715 case X86::BI__builtin_ia32_vpshufbitqmb512_mask:
2716 cgm.errorNYI(expr->getSourceRange(),
2717 std::string("unimplemented X86 builtin call: ") +
2718 getContext().BuiltinInfo.getName(builtinID));
2719 return {};
2720 case X86::BI__builtin_ia32_cmpeqps:
2721 case X86::BI__builtin_ia32_cmpeqpd:
2722 return emitVectorFCmp(*this, *expr, ops, cir::CmpOpKind::eq,
2723 /*shouldInvert=*/false);
2724 case X86::BI__builtin_ia32_cmpltps:
2725 case X86::BI__builtin_ia32_cmpltpd:
2726 return emitVectorFCmp(*this, *expr, ops, cir::CmpOpKind::lt,
2727 /*shouldInvert=*/false);
2728 case X86::BI__builtin_ia32_cmpleps:
2729 case X86::BI__builtin_ia32_cmplepd:
2730 return emitVectorFCmp(*this, *expr, ops, cir::CmpOpKind::le,
2731 /*shouldInvert=*/false);
2732 case X86::BI__builtin_ia32_cmpunordps:
2733 case X86::BI__builtin_ia32_cmpunordpd:
2734 return emitVectorFCmp(*this, *expr, ops, cir::CmpOpKind::uno,
2735 /*shouldInvert=*/false);
2736 case X86::BI__builtin_ia32_cmpneqps:
2737 case X86::BI__builtin_ia32_cmpneqpd:
2738 return emitVectorFCmp(*this, *expr, ops, cir::CmpOpKind::ne,
2739 /*shouldInvert=*/false);
2740 case X86::BI__builtin_ia32_cmpnltps:
2741 case X86::BI__builtin_ia32_cmpnltpd:
2742 return emitVectorFCmp(*this, *expr, ops, cir::CmpOpKind::lt,
2743 /*shouldInvert=*/true);
2744 case X86::BI__builtin_ia32_cmpnleps:
2745 case X86::BI__builtin_ia32_cmpnlepd:
2746 return emitVectorFCmp(*this, *expr, ops, cir::CmpOpKind::le,
2747 /*shouldInvert=*/true);
2748 case X86::BI__builtin_ia32_cmpordps:
2749 case X86::BI__builtin_ia32_cmpordpd:
2750 return emitVectorFCmp(*this, *expr, ops, cir::CmpOpKind::uno,
2751 /*shouldInvert=*/true);
2752 case X86::BI__builtin_ia32_cmpph128_mask:
2753 case X86::BI__builtin_ia32_cmpph256_mask:
2754 case X86::BI__builtin_ia32_cmpph512_mask:
2755 case X86::BI__builtin_ia32_cmpps128_mask:
2756 case X86::BI__builtin_ia32_cmpps256_mask:
2757 case X86::BI__builtin_ia32_cmpps512_mask:
2758 case X86::BI__builtin_ia32_cmppd128_mask:
2759 case X86::BI__builtin_ia32_cmppd256_mask:
2760 case X86::BI__builtin_ia32_cmppd512_mask:
2761 case X86::BI__builtin_ia32_vcmpbf16512_mask:
2762 case X86::BI__builtin_ia32_vcmpbf16256_mask:
2763 case X86::BI__builtin_ia32_vcmpbf16128_mask:
2764 case X86::BI__builtin_ia32_cmpps:
2765 case X86::BI__builtin_ia32_cmpps256:
2766 case X86::BI__builtin_ia32_cmppd:
2767 case X86::BI__builtin_ia32_cmppd256:
2768 case X86::BI__builtin_ia32_cmpeqss:
2769 case X86::BI__builtin_ia32_cmpltss:
2770 case X86::BI__builtin_ia32_cmpless:
2771 case X86::BI__builtin_ia32_cmpunordss:
2772 case X86::BI__builtin_ia32_cmpneqss:
2773 case X86::BI__builtin_ia32_cmpnltss:
2774 case X86::BI__builtin_ia32_cmpnless:
2775 case X86::BI__builtin_ia32_cmpordss:
2776 case X86::BI__builtin_ia32_cmpeqsd:
2777 case X86::BI__builtin_ia32_cmpltsd:
2778 case X86::BI__builtin_ia32_cmplesd:
2779 case X86::BI__builtin_ia32_cmpunordsd:
2780 case X86::BI__builtin_ia32_cmpneqsd:
2781 case X86::BI__builtin_ia32_cmpnltsd:
2782 case X86::BI__builtin_ia32_cmpnlesd:
2783 case X86::BI__builtin_ia32_cmpordsd:
2784 cgm.errorNYI(expr->getSourceRange(),
2785 std::string("unimplemented X86 builtin call: ") +
2786 getContext().BuiltinInfo.getName(builtinID));
2787 return {};
2788 case X86::BI__builtin_ia32_vcvtph2ps_mask:
2789 case X86::BI__builtin_ia32_vcvtph2ps256_mask:
2790 case X86::BI__builtin_ia32_vcvtph2ps512_mask: {
2791 mlir::Location loc = getLoc(expr->getExprLoc());
2792 return emitX86CvtF16ToFloatExpr(builder, loc, ops,
2793 convertType(expr->getType()));
2794 }
2795 case X86::BI__builtin_ia32_cvtneps2bf16_128_mask: {
2796 mlir::Location loc = getLoc(expr->getExprLoc());
2797 cir::VectorType resTy = cast<cir::VectorType>(convertType(expr->getType()));
2798
2799 cir::VectorType inputTy = cast<cir::VectorType>(ops[0].getType());
2800 unsigned numElts = inputTy.getSize();
2801
2802 mlir::Value mask = getMaskVecValue(builder, loc, ops[2], numElts);
2803
2805 args.push_back(ops[0]);
2806 args.push_back(ops[1]);
2807 args.push_back(mask);
2808
2809 return builder.emitIntrinsicCallOp(
2810 loc, "x86.avx512bf16.mask.cvtneps2bf16.128", resTy, args);
2811 }
2812 case X86::BI__builtin_ia32_cvtneps2bf16_256_mask:
2813 case X86::BI__builtin_ia32_cvtneps2bf16_512_mask: {
2814 mlir::Location loc = getLoc(expr->getExprLoc());
2815 cir::VectorType resTy = cast<cir::VectorType>(convertType(expr->getType()));
2816 StringRef intrinsicName;
2817 if (builtinID == X86::BI__builtin_ia32_cvtneps2bf16_256_mask) {
2818 intrinsicName = "x86.avx512bf16.cvtneps2bf16.256";
2819 } else {
2820 assert(builtinID == X86::BI__builtin_ia32_cvtneps2bf16_512_mask);
2821 intrinsicName = "x86.avx512bf16.cvtneps2bf16.512";
2822 }
2823
2824 mlir::Value res = builder.emitIntrinsicCallOp(loc, intrinsicName, resTy,
2825 mlir::ValueRange{ops[0]});
2826
2827 return emitX86Select(builder, loc, ops[2], res, ops[1]);
2828 }
2829 case X86::BI__cpuid:
2830 case X86::BI__cpuidex: {
2831 mlir::Location loc = getLoc(expr->getExprLoc());
2832 mlir::Value subFuncId = builtinID == X86::BI__cpuidex
2833 ? ops[2]
2834 : builder.getConstInt(loc, sInt32Ty, 0);
2835 cir::CpuIdOp::create(builder, loc, /*cpuInfo=*/ops[0],
2836 /*functionId=*/ops[1], /*subFunctionId=*/subFuncId);
2837 return mlir::Value{};
2838 }
2839 case X86::BI__emul:
2840 case X86::BI__emulu:
2841 case X86::BI__mulh:
2842 case X86::BI__umulh:
2843 case X86::BI_mul128:
2844 case X86::BI_umul128: {
2845 cgm.errorNYI(expr->getSourceRange(),
2846 std::string("unimplemented X86 builtin call: ") +
2847 getContext().BuiltinInfo.getName(builtinID));
2848 return mlir::Value{};
2849 }
2850 case X86::BI__faststorefence: {
2851 cir::AtomicFenceOp::create(
2852 builder, getLoc(expr->getExprLoc()),
2853 cir::MemOrder::SequentiallyConsistent,
2854 cir::SyncScopeKindAttr::get(&getMLIRContext(),
2855 cir::SyncScopeKind::System));
2856 return mlir::Value{};
2857 }
2858 case X86::BI__shiftleft128:
2859 case X86::BI__shiftright128: {
2860 // Flip low/high ops and zero-extend amount to matching type.
2861 // shiftleft128(Low, High, Amt) -> fshl(High, Low, Amt)
2862 // shiftright128(Low, High, Amt) -> fshr(High, Low, Amt)
2863 std::swap(ops[0], ops[1]);
2864
2865 // Zero-extend shift amount to i64 if needed
2866 auto amtTy = mlir::cast<cir::IntType>(ops[2].getType());
2867 cir::IntType i64Ty = builder.getUInt64Ty();
2868
2869 if (amtTy != i64Ty)
2870 ops[2] = builder.createIntCast(ops[2], i64Ty);
2871
2872 const StringRef intrinsicName =
2873 (builtinID == X86::BI__shiftleft128) ? "fshl" : "fshr";
2874 return builder.emitIntrinsicCallOp(
2875 getLoc(expr->getExprLoc()), intrinsicName, i64Ty,
2876 mlir::ValueRange{ops[0], ops[1], ops[2]});
2877 }
2878 case X86::BI_ReadWriteBarrier:
2879 case X86::BI_ReadBarrier:
2880 case X86::BI_WriteBarrier: {
2881 cir::AtomicFenceOp::create(
2882 builder, getLoc(expr->getExprLoc()),
2883 cir::MemOrder::SequentiallyConsistent,
2884 cir::SyncScopeKindAttr::get(&getMLIRContext(),
2885 cir::SyncScopeKind::SingleThread));
2886 return mlir::Value{};
2887 }
2888 case X86::BI_AddressOfReturnAddress: {
2889 mlir::Location loc = getLoc(expr->getExprLoc());
2890 mlir::Value addr =
2891 cir::AddrOfReturnAddrOp::create(builder, loc, allocaInt8PtrTy);
2892 return builder.createCast(loc, cir::CastKind::bitcast, addr, voidPtrTy);
2893 }
2894 case X86::BI__stosb:
2895 case X86::BI__ud2:
2896 case X86::BI__int2c:
2897 case X86::BI__readfsbyte:
2898 case X86::BI__readfsword:
2899 case X86::BI__readfsdword:
2900 case X86::BI__readfsqword:
2901 case X86::BI__readgsbyte:
2902 case X86::BI__readgsword:
2903 case X86::BI__readgsdword:
2904 case X86::BI__readgsqword: {
2905 cgm.errorNYI(expr->getSourceRange(),
2906 std::string("unimplemented X86 builtin call: ") +
2907 getContext().BuiltinInfo.getName(builtinID));
2908 return mlir::Value{};
2909 }
2910 case X86::BI__builtin_ia32_encodekey128_u32: {
2911 return emitEncodeKey(&getMLIRContext(), builder, getLoc(expr->getExprLoc()),
2912 {ops[0], ops[1]}, ops[2], 6, "x86.encodekey128", 3);
2913 }
2914 case X86::BI__builtin_ia32_encodekey256_u32: {
2915
2916 return emitEncodeKey(&getMLIRContext(), builder, getLoc(expr->getExprLoc()),
2917 {ops[0], ops[1], ops[2]}, ops[3], 7,
2918 "x86.encodekey256", 4);
2919 }
2920
2921 case X86::BI__builtin_ia32_aesenc128kl_u8:
2922 case X86::BI__builtin_ia32_aesdec128kl_u8:
2923 case X86::BI__builtin_ia32_aesenc256kl_u8:
2924 case X86::BI__builtin_ia32_aesdec256kl_u8: {
2925 llvm::StringRef intrinsicName;
2926 switch (builtinID) {
2927 default:
2928 llvm_unreachable("Unexpected builtin");
2929 case X86::BI__builtin_ia32_aesenc128kl_u8:
2930 intrinsicName = "x86.aesenc128kl";
2931 break;
2932 case X86::BI__builtin_ia32_aesdec128kl_u8:
2933 intrinsicName = "x86.aesdec128kl";
2934 break;
2935 case X86::BI__builtin_ia32_aesenc256kl_u8:
2936 intrinsicName = "x86.aesenc256kl";
2937 break;
2938 case X86::BI__builtin_ia32_aesdec256kl_u8:
2939 intrinsicName = "x86.aesdec256kl";
2940 break;
2941 }
2942
2943 return emitX86Aes(builder, getLoc(expr->getExprLoc()), intrinsicName,
2944 convertType(expr->getType()), ops);
2945 }
2946 case X86::BI__builtin_ia32_aesencwide128kl_u8:
2947 case X86::BI__builtin_ia32_aesdecwide128kl_u8:
2948 case X86::BI__builtin_ia32_aesencwide256kl_u8:
2949 case X86::BI__builtin_ia32_aesdecwide256kl_u8: {
2950 llvm::StringRef intrinsicName;
2951 switch (builtinID) {
2952 default:
2953 llvm_unreachable("Unexpected builtin");
2954 case X86::BI__builtin_ia32_aesencwide128kl_u8:
2955 intrinsicName = "x86.aesencwide128kl";
2956 break;
2957 case X86::BI__builtin_ia32_aesdecwide128kl_u8:
2958 intrinsicName = "x86.aesdecwide128kl";
2959 break;
2960 case X86::BI__builtin_ia32_aesencwide256kl_u8:
2961 intrinsicName = "x86.aesencwide256kl";
2962 break;
2963 case X86::BI__builtin_ia32_aesdecwide256kl_u8:
2964 intrinsicName = "x86.aesdecwide256kl";
2965 break;
2966 }
2967
2968 return emitX86Aeswide(builder, getLoc(expr->getExprLoc()), intrinsicName,
2969 convertType(expr->getType()), ops);
2970 }
2971 case X86::BI__builtin_ia32_vfcmaddcph512_mask:
2972 case X86::BI__builtin_ia32_vfmaddcph512_mask:
2973 case X86::BI__builtin_ia32_vfcmaddcsh_round_mask:
2974 case X86::BI__builtin_ia32_vfmaddcsh_round_mask:
2975 case X86::BI__builtin_ia32_vfcmaddcsh_round_mask3:
2976 case X86::BI__builtin_ia32_vfmaddcsh_round_mask3:
2977 case X86::BI__builtin_ia32_prefetchi:
2978 cgm.errorNYI(expr->getSourceRange(),
2979 std::string("unimplemented X86 builtin call: ") +
2980 getContext().BuiltinInfo.getName(builtinID));
2981 return mlir::Value{};
2982 }
2983}
#define X86_CPU_TYPE(ENUM, STR, ABI_VALUE)
#define X86_CPU_SUBTYPE(ENUM, STR, ABI_VALUE)
#define X86_VENDOR(ENUM, STRING, ABI_VALUE)
Defines enum values for all the target-independent builtin functions.
static mlir::Value emitX86MaskLogic(CIRGenBuilderTy &builder, mlir::Location loc, SmallVectorImpl< mlir::Value > &ops, bool invertLHS=false)
static mlir::Value emitX86vpcom(CIRGenBuilderTy &builder, mlir::Location loc, llvm::SmallVector< mlir::Value > ops, bool isSigned)
static std::optional< mlir::Value > emitX86ConvertToMask(CIRGenFunction &cgf, CIRGenBuilderTy &builder, mlir::Value in, mlir::Location loc)
static mlir::Value emitX86CompressExpand(CIRGenBuilderTy &builder, mlir::Location loc, mlir::Value source, mlir::Value mask, mlir::Value inputVector, const std::string &id)
static void computeFullLaneShuffleMask(CIRGenFunction &cgf, const mlir::Value vec, uint32_t imm, const bool isShufP, llvm::SmallVectorImpl< int64_t > &outIndices)
static mlir::Value emitX86VPerm2f128(CIRGenBuilderTy &builder, mlir::Location loc, llvm::SmallVector< mlir::Value > ops)
static std::optional< mlir::Value > emitX86SExtMask(CIRGenBuilderTy &builder, mlir::Value op, mlir::Type dstTy, mlir::Location loc)
static mlir::Value emitX86Round(CIRGenFunction &cgf, unsigned builtinID, const CallExpr *expr, SmallVector< mlir::Value > &ops)
static mlir::Value emitX86PackedByteShift(CIRGenBuilderTy &builder, unsigned builtinID, mlir::Location loc, llvm::ArrayRef< mlir::Value > ops, llvm::Boolean isLeftShift)
static std::optional< mlir::Value > emitX86MaskedCompare(CIRGenBuilderTy &builder, unsigned cc, bool isSigned, ArrayRef< mlir::Value > ops, mlir::Location loc)
static mlir::Value emitPrefetch(CIRGenFunction &cgf, unsigned builtinID, const CallExpr *e, const SmallVector< mlir::Value > &ops)
static mlir::Value getMaskZeroBitAsBool(CIRGenBuilderTy &builder, mlir::Location loc, mlir::Value mask)
static mlir::Value emitX86Aeswide(CIRGenBuilderTy &builder, mlir::Location loc, llvm::StringRef intrinsicName, mlir::Type retType, llvm::ArrayRef< mlir::Value > ops)
static mlir::Value emitX86MaskTest(CIRGenBuilderTy &builder, mlir::Location loc, const std::string &intrinsicName, SmallVectorImpl< mlir::Value > &ops)
static mlir::Value emitEncodeKey(mlir::MLIRContext *context, CIRGenBuilderTy &builder, const mlir::Location &location, mlir::ValueRange inputOperands, mlir::Value outputOperand, std::uint8_t vecOutputCount, const std::string &intrinsicName, std::uint8_t numResults)
static mlir::Value emitVecInsert(CIRGenBuilderTy &builder, mlir::Location loc, mlir::Value vec, mlir::Value value, mlir::Value indexOp)
static mlir::Value emitX86Fpclass(CIRGenBuilderTy &builder, mlir::Location loc, unsigned builtinID, SmallVectorImpl< mlir::Value > &ops)
static mlir::Value emitX86MaskedLoad(CIRGenBuilderTy &builder, ArrayRef< mlir::Value > ops, llvm::Align alignment, mlir::Location loc)
static mlir::Value emitX86MaskUnpack(CIRGenBuilderTy &builder, mlir::Location loc, const std::string &intrinsicName, SmallVectorImpl< mlir::Value > &ops)
static mlir::Value emitVectorFCmp(CIRGenFunction &cgf, const CallExpr &expr, llvm::SmallVector< mlir::Value > &ops, cir::CmpOpKind pred, bool shouldInvert)
static cir::VecShuffleOp emitPshufWord(CIRGenBuilderTy &builder, const mlir::Value vec, const mlir::Value immediate, const mlir::Location loc, const bool isLow)
static mlir::Value emitX86MaskedCompareResult(CIRGenBuilderTy &builder, mlir::Value cmp, unsigned numElts, mlir::Value maskIn, mlir::Location loc)
static mlir::Value emitX86Select(CIRGenBuilderTy &builder, mlir::Location loc, mlir::Value mask, mlir::Value op0, mlir::Value op1)
static mlir::Value emitX86Aes(CIRGenBuilderTy &builder, mlir::Location loc, llvm::StringRef intrinsicName, mlir::Type retType, llvm::ArrayRef< mlir::Value > ops)
static mlir::Value emitX86CvtF16ToFloatExpr(CIRGenBuilderTy &builder, mlir::Location loc, llvm::ArrayRef< mlir::Value > ops, mlir::Type dstTy)
static mlir::Value emitX86FunnelShift(CIRGenBuilderTy &builder, mlir::Location location, mlir::Value &op0, mlir::Value &op1, mlir::Value &amt, bool isRight)
static mlir::Value emitX86Muldq(CIRGenBuilderTy &builder, mlir::Location loc, bool isSigned, SmallVectorImpl< mlir::Value > &ops, unsigned opTypePrimitiveSizeInBits)
static mlir::Value getMaskVecValue(CIRGenBuilderTy &builder, mlir::Location loc, mlir::Value mask, unsigned numElems)
static mlir::Value emitX86MaskAddLogic(CIRGenBuilderTy &builder, mlir::Location loc, const std::string &intrinsicName, SmallVectorImpl< mlir::Value > &ops)
static mlir::Value emitX86CompressStore(CIRGenBuilderTy &builder, mlir::Location loc, ArrayRef< mlir::Value > ops)
static mlir::Value emitX86ScalarSelect(CIRGenBuilderTy &builder, mlir::Location loc, mlir::Value mask, mlir::Value op0, mlir::Value op1)
TokenType getType() const
Returns the token's type, e.g.
#define ENUM(NAME, LIT)
Enumerates target-specific builtins in their own namespaces within namespace clang.
cir::FenvAttr getConstrainedFPAttr()
Build the #cir.fenv attribute describing the constrained floating-point environment currently in effe...
mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ, const llvm::APInt &val)
mlir::Value createShift(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, bool isShiftLeft)
cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc)
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr)
mlir::Value createCast(mlir::Location loc, cir::CastKind kind, mlir::Value src, mlir::Type newTy)
cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base, mlir::Value stride)
mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy)
mlir::Value createAnd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createExtractElement(mlir::Location loc, mlir::Value vec, uint64_t idx)
cir::VecCmpOp createVecCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
Compares lhs and rhs element-wise.
mlir::Value createIntCast(mlir::Value src, mlir::Type newTy)
mlir::Value createInsertElement(mlir::Location loc, mlir::Value vec, mlir::Value newElt, uint64_t idx)
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
mlir::Value createNot(mlir::Location loc, mlir::Value value)
mlir::Value createSelect(mlir::Location loc, mlir::Value condition, mlir::Value trueValue, mlir::Value falseValue)
mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob=OverflowBehavior::None)
void setDefaultConstrainedExcept(clang::LangOptions::FPExceptionModeKind newExcept)
Set the exception handling to be used with constrained floating point.
bool getIsFPConstrained() const
Query for the use of constrained floating point math.
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
cir::BoolType getBoolTy()
llvm::TypeSize getTypeSizeInBits(mlir::Type ty) const
C++ view class that accepts both !cir.struct and !cir.union types.
Definition CIRTypes.h:149
static llvm::SmallVector< RecordMemberKind > getAllDataKinds(llvm::ArrayRef< mlir::Type > members)
One Data kind per member.
Definition CIRTypes.cpp:162
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error, unsigned *IntegerConstantArgs=nullptr) const
Return the type for the specified builtin.
@ GE_None
No error.
mlir::Value getPointer() const
Definition Address.h:98
cir::ConstantOp getUInt64(uint64_t c, mlir::Location loc)
mlir::Value emitIntrinsicCallOp(mlir::Location loc, const llvm::StringRef str, const mlir::Type &resTy, Operands &&...op)
cir::IntType getSIntNTy(int n)
cir::ConstantOp getUInt32(uint32_t c, mlir::Location loc)
cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1, mlir::Value vec2, llvm::ArrayRef< mlir::Attribute > maskAttrs)
mlir::Value createMaskedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr, llvm::Align alignment, mlir::Value mask, mlir::Value passThru)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, bool isNontemporal=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
cir::LoadOp createAlignedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr, llvm::MaybeAlign align)
cir::ConstantOp getZero(mlir::Location loc, mlir::Type ty)
cir::StructType getAnonRecordTy(llvm::ArrayRef< mlir::Type > members, bool packed, llvm::ArrayRef< cir::RecordMemberKind > memberKinds)
Get a CIR anonymous struct type.
cir::ConstantOp getSInt32(int32_t c, mlir::Location loc)
cir::IntType getUIntNTy(int n)
mlir::Value getArrayElement(mlir::Location arrayLocBegin, mlir::Location arrayLocEnd, mlir::Value arrayPtr, mlir::Type eltTy, mlir::Value idx, bool shouldDecay)
Create a cir.ptr_stride operation to get access to an array element.
mlir::Type convertType(clang::QualType t)
mlir::Value emitX86CpuIs(const CallExpr *expr)
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
mlir::Value emitX86CpuInit(mlir::Location loc)
mlir::Value emitX86CpuSupports(const CallExpr *expr)
static int64_t getZExtIntValueFromConstOp(mlir::Value val)
Get zero-extended integer from a mlir::Value that is an int constant or a constant op.
cir::FastMathFlagsAttr getFastMathFlagsAttr(cir::FastMathFlags fastMathFlags)
Create a CIR fast-math attribute from the specified flags.
cir::FastMathFlags getCurrentFastMathFlags() const
Convert the active Clang floating-point options to CIR fast-math flags.
static int64_t getSExtIntValueFromConstOp(mlir::Value val)
Get integer from a mlir::Value that is an int constant or a constant op.
std::optional< mlir::Value > emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr)
cir::GetGlobalOp createGetCpuModel(mlir::Location loc)
CIRGenBuilderTy & getBuilder()
mlir::MLIRContext & getMLIRContext()
cir::GetGlobalOp createGetCpuFeatures2(mlir::Location loc)
clang::ASTContext & getContext() const
Address createMemTemp(QualType t, mlir::Location loc, const Twine &name="tmp", Address *alloca=nullptr, mlir::OpBuilder::InsertPoint ip={})
Create a temporary memory object of the given type, with appropriate alignmen and cast it to the defa...
mlir::Value emitScalarOrConstFoldImmArg(unsigned iceArguments, unsigned idx, const Expr *argExpr)
const cir::CIRDataLayout & getDataLayout() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2991
static CharUnits One()
Construct a CharUnits quantity of one.
Definition CharUnits.h:55
static CharUnits fromQuantity(QuantityType Quantity)
Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:58
This represents one expression.
Definition Expr.h:113
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:283
@ FPE_Ignore
Assume that floating-point exceptions are masked.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
Top level wrappers for InstallAPI frontend operations.
@ Default
Set to the current date and time.
U cast(CodeGen::Address addr)
Definition Address.h:327
__builtin_bitreverse32 uint32_t __builtin_riscv_aaddu_u32 __builtin_riscv_asubu_u32 __builtin_elementwise_add_sat __builtin_elementwise_sub_sat int32_t uint32_t uint32_t __builtin_riscv_mhacc_i32 __builtin_riscv_mhaccu_u32 __builtin_riscv_mhaccsu_i32 __builtin_riscv_mulq_i32 uint8_t
static bool msvcBuiltins()
static bool handleBuiltinICEArguments()
static bool setDLLStorageClass()
cir::PointerType allocaInt8PtrTy
void* in alloca address space
cir::PointerType voidPtrTy
void* in address space 0