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