clang 24.0.0git
CIRGenBuiltin.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 Builtin calls as CIR or a function call to be
10// later resolved.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CIRGenCall.h"
15#include "CIRGenFunction.h"
16#include "CIRGenModule.h"
17#include "CIRGenValue.h"
18#include "mlir/IR/BuiltinAttributes.h"
19#include "mlir/IR/Value.h"
20#include "mlir/Support/LLVM.h"
21#include "clang/AST/DeclBase.h"
22#include "clang/AST/Expr.h"
29#include "llvm/ADT/STLExtras.h"
30#include "llvm/IR/Intrinsics.h"
31#include "llvm/Support/ErrorHandling.h"
32
33using namespace clang;
34using namespace clang::CIRGen;
35using namespace llvm;
36
37static bool shouldEmitBuiltinAsIR(unsigned builtinID,
38 const Builtin::Context &bi,
39 const CIRGenFunction &cgf) {
40 if (!cgf.cgm.getLangOpts().MathErrno &&
44 switch (builtinID) {
45 default:
46 return false;
47 case Builtin::BIlogbf:
48 case Builtin::BI__builtin_logbf:
49 case Builtin::BIlogb:
50 case Builtin::BI__builtin_logb:
51 case Builtin::BIscalbnf:
52 case Builtin::BI__builtin_scalbnf:
53 case Builtin::BIscalbn:
54 case Builtin::BI__builtin_scalbn:
55 return true;
56 }
57 }
58 return false;
59}
60
62 const CallExpr *e, mlir::Operation *calleeValue) {
63 CIRGenCallee callee = CIRGenCallee::forDirect(calleeValue, GlobalDecl(fd));
64 return cgf.emitCall(e->getCallee()->getType(), callee, e, ReturnValueSlot());
65}
66
67template <typename Op, typename... Args>
68static mlir::Value createBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e,
69 mlir::Value arg, Args... args) {
70 CIRGenBuilderTy &builder = cgf.getBuilder();
71 mlir::Location loc = cgf.getLoc(e->getSourceRange());
72 auto op = Op::create(builder, loc, arg, args...);
73 mlir::Value result = op.getResult();
74 mlir::Type resultTy = cgf.convertType(e->getType());
75 if (resultTy != result.getType())
76 result = builder.createIntCast(result, resultTy);
77 return result;
78}
79
80template <typename Op, typename... Args>
82 Args... args) {
83 mlir::Value arg = cgf.emitScalarExpr(e->getArg(0));
84 return RValue::get(createBuiltinBitOp<Op>(cgf, e, arg, args...));
85}
86
87/// Emit a clz/ctz bit op with optional fallback for __builtin_c[lt]zg.
88/// When a fallback is present, the result is the fallback value if the input is
89/// zero, otherwise the bit count.
90template <typename Op>
92 const CallExpr *e) {
93 bool hasFallback = e->getNumArgs() > 1;
94 bool poisonZero = hasFallback || cgf.getTarget().isCLZForZeroUndef();
95
96 if (!hasFallback) {
98 return emitBuiltinBitOp<Op>(cgf, e, poisonZero);
99 }
100
102 mlir::Value arg = cgf.emitScalarExpr(e->getArg(0));
103 mlir::Value result = createBuiltinBitOp<Op>(cgf, e, arg, poisonZero);
104
105 CIRGenBuilderTy &builder = cgf.getBuilder();
106 mlir::Location loc = cgf.getLoc(e->getSourceRange());
107 mlir::Value zero = builder.getNullValue(arg.getType(), loc);
108 mlir::Value isZero =
109 builder.createCompare(loc, cir::CmpOpKind::eq, arg, zero);
110 mlir::Value fallbackValue = cgf.emitScalarExpr(e->getArg(1));
111 return RValue::get(builder.createSelect(loc, isZero, fallbackValue, result));
112}
113
114/// Emit the conversions required to turn the given value into an
115/// integer of the given size.
116static mlir::Value emitToInt(CIRGenFunction &cgf, mlir::Value v, QualType t,
117 cir::IntType intType) {
118 v = cgf.emitToMemory(v, t);
119
120 if (mlir::isa<cir::PointerType>(v.getType()))
121 return cgf.getBuilder().createPtrToInt(v, intType);
122
123 assert(v.getType() == intType);
124 return v;
125}
126
127static mlir::Value emitFromInt(CIRGenFunction &cgf, mlir::Value v, QualType t,
128 mlir::Type resultType) {
129 v = cgf.emitFromMemory(v, t);
130
131 if (mlir::isa<cir::PointerType>(resultType))
132 return cgf.getBuilder().createIntToPtr(v, resultType);
133
134 assert(v.getType() == resultType);
135 return v;
136}
137
138static mlir::Value emitSignBit(mlir::Location loc, CIRGenFunction &cgf,
139 mlir::Value val) {
141 cir::SignBitOp returnValue = cgf.getBuilder().createSignBit(loc, val);
142 return returnValue->getResult(0);
143}
144
146 ASTContext &astContext = cgf.getContext();
147 Address ptr = cgf.emitPointerWithAlignment(e->getArg(0));
148 unsigned bytes =
149 mlir::isa<cir::PointerType>(ptr.getElementType())
150 ? astContext.getTypeSizeInChars(astContext.VoidPtrTy).getQuantity()
153
154 unsigned align = ptr.getAlignment().getQuantity();
155 if (align % bytes != 0) {
156 DiagnosticsEngine &diags = cgf.cgm.getDiags();
157 diags.Report(e->getBeginLoc(), diag::warn_sync_op_misaligned);
158 // Force address to be at least naturally-aligned.
160 }
161 return ptr;
162}
163
164/// Utility to insert an atomic instruction based on Intrinsic::ID
165/// and the expression node.
166mlir::Value CIRGenFunction::makeBinaryAtomicValue(cir::AtomicFetchKind kind,
167 const CallExpr *expr,
168 mlir::Type *originalArgType,
169 mlir::Value *emittedArgValue,
170 cir::MemOrder ordering) {
171 CIRGenFunction &cgf = *this;
172
173 QualType type = expr->getType();
174 QualType ptrType = expr->getArg(0)->getType();
175
176 assert(ptrType->isPointerType());
177 assert(
180 expr->getArg(1)->getType()));
181
182 Address destAddr = checkAtomicAlignment(cgf, expr);
183 CIRGenBuilderTy &builder = cgf.getBuilder();
184
185 mlir::Value val = cgf.emitScalarExpr(expr->getArg(1));
186 mlir::Type valueType = val.getType();
187 mlir::Value destValue = destAddr.emitRawPointer();
188
189 if (ptrType->getPointeeType()->isPointerType()) {
190 // Pointer to pointer
191 // `cir.atomic.fetch` expects a pointer to an integer type, so we cast
192 // ptr<ptr<T>> to ptr<intPtrSize>
193 cir::IntType ptrSizeInt =
194 builder.getSIntNTy(cgf.getContext().getTypeSize(ptrType));
195 destValue =
196 builder.createBitcast(destValue, builder.getPointerTo(ptrSizeInt));
197 val = emitToInt(cgf, val, type, ptrSizeInt);
198 } else {
199 // Pointer to integer type
200 cir::IntType intType =
202 ? builder.getUIntNTy(cgf.getContext().getTypeSize(type))
203 : builder.getSIntNTy(cgf.getContext().getTypeSize(type));
204 val = emitToInt(cgf, val, type, intType);
205 }
206
207 // This output argument is needed for post atomic fetch operations
208 // that calculate the result of the operation as return value of
209 // <binop>_and_fetch builtins. The `AtomicFetch` operation only updates the
210 // memory location and returns the old value.
211 if (emittedArgValue) {
212 *emittedArgValue = val;
213 assert(originalArgType != nullptr &&
214 "originalArgType must be provided when emittedArgValue is set");
215 *originalArgType = valueType;
216 }
217
218 auto rmwi = cir::AtomicFetchOp::create(
219 builder, cgf.getLoc(expr->getSourceRange()), destValue, val, kind,
220 ordering, cir::SyncScopeKind::System, false, /* is volatile */
221 true); /* fetch first */
222 return rmwi->getResult(0);
223}
224
226 cir::AtomicFetchKind atomicOpkind,
227 const CallExpr *e) {
228 return RValue::get(cgf.makeBinaryAtomicValue(atomicOpkind, e));
229}
230
231template <typename BinOp>
233 cir::AtomicFetchKind atomicOpkind,
234 const CallExpr *e, bool invert = false) {
235 mlir::Value emittedArgValue;
236 mlir::Type originalArgType;
237 clang::QualType typ = e->getType();
238 mlir::Value result = cgf.makeBinaryAtomicValue(
239 atomicOpkind, e, &originalArgType, &emittedArgValue);
241 result = BinOp::create(builder, result.getLoc(), result, emittedArgValue);
242
243 if (invert)
244 result = builder.createNot(result);
245
246 result = emitFromInt(cgf, result, typ, originalArgType);
247 return RValue::get(result);
248}
249
251 cir::SyncScopeKind syncScope) {
252 CIRGenBuilderTy &builder = cgf.getBuilder();
253 mlir::Location loc = cgf.getLoc(expr->getSourceRange());
254
255 auto emitAtomicOpCallBackFn = [&](cir::MemOrder memOrder) {
256 cir::AtomicFenceOp::create(
257 builder, loc, memOrder,
258 cir::SyncScopeKindAttr::get(&cgf.getMLIRContext(), syncScope));
259 };
260
261 cgf.emitAtomicExprWithMemOrder(expr->getArg(0), /*isStore*/ false,
262 /*isLoad*/ false, /*isFence*/ true,
263 emitAtomicOpCallBackFn);
264}
265
266// Emit a runtime call to bool __atomic_is_lock_free(size_t size, void *ptr).
267// For the __c11 builtin the pointer is null, since an _Atomic object is always
268// suitably aligned.
270 unsigned builtinID) {
271 CIRGenBuilderTy &builder = cgf.getBuilder();
272 mlir::Location loc = cgf.getLoc(e->getExprLoc());
273
274 mlir::Type sizeTy = cgf.convertType(cgf.getContext().getSizeType());
275 mlir::Value size = cgf.emitScalarExpr(e->getArg(0));
276 mlir::Value ptr;
277 if (builtinID == Builtin::BI__atomic_is_lock_free)
278 ptr = builder.createBitcast(cgf.emitScalarExpr(e->getArg(1)),
279 builder.getVoidPtrTy());
280 else
281 ptr = builder.getNullPtr(builder.getVoidPtrTy(), loc);
282
283 cir::FuncOp func = cgf.cgm.createRuntimeFunction(
284 cir::FuncType::get({sizeTy, builder.getVoidPtrTy()}, builder.getBoolTy()),
285 "__atomic_is_lock_free");
286 return RValue::get(
287 builder.createCallOp(loc, func, mlir::ValueRange{size, ptr}).getResult());
288}
289
290namespace {
291struct WidthAndSignedness {
292 unsigned width;
293 bool isSigned;
294};
295} // namespace
296
297static WidthAndSignedness
299 const clang::QualType type) {
300 assert(type->isIntegerType() && "Given type is not an integer.");
301 unsigned width = type->isBooleanType() ? 1
302 : type->isBitIntType() ? astContext.getIntWidth(type)
303 : astContext.getTypeInfo(type).Width;
304 bool isSigned = type->isSignedIntegerType();
305 return {width, isSigned};
306}
307
308/// Create a checked overflow arithmetic op and return its result and overflow
309/// flag.
310template <typename OpTy>
311static std::pair<mlir::Value, mlir::Value>
312emitOverflowOp(CIRGenBuilderTy &builder, mlir::Location loc,
313 mlir::Type resultTy, mlir::Value lhs, mlir::Value rhs) {
314 auto op = OpTy::create(builder, loc, resultTy, lhs, rhs);
315 return {op.getResult(), op.getOverflow()};
316}
317
318// Given one or more integer types, this function produces an integer type that
319// encompasses them: any value in one of the given types could be expressed in
320// the encompassing type.
321static struct WidthAndSignedness
322EncompassingIntegerType(ArrayRef<struct WidthAndSignedness> types) {
323 assert(types.size() > 0 && "Empty list of types.");
324
325 // If any of the given types is signed, we must return a signed type.
326 bool isSigned = llvm::any_of(types, [](const auto &t) { return t.isSigned; });
327
328 // The encompassing type must have a width greater than or equal to the width
329 // of the specified types. Additionally, if the encompassing type is signed,
330 // its width must be strictly greater than the width of any unsigned types
331 // given.
332 unsigned width = 0;
333 for (const auto &type : types)
334 width = std::max(width, type.width + (isSigned && !type.isSigned));
335
336 return {width, isSigned};
337}
338
339RValue CIRGenFunction::emitRotate(const CallExpr *e, bool isRotateLeft) {
340 mlir::Value input = emitScalarExpr(e->getArg(0));
341 mlir::Value amount = emitScalarExpr(e->getArg(1));
342
343 // TODO(cir): MSVC flavor bit rotate builtins use different types for input
344 // and amount, but cir.rotate requires them to have the same type. Cast amount
345 // to the type of input when necessary.
347
348 auto r = cir::RotateOp::create(builder, getLoc(e->getSourceRange()), input,
349 amount, isRotateLeft);
350 return RValue::get(r);
351}
352
353template <class Operation>
355 const CallExpr &e) {
356 mlir::Value arg = cgf.emitScalarExpr(e.getArg(0));
357
358 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, &e);
360
361 auto call =
362 Operation::create(cgf.getBuilder(), arg.getLoc(), arg.getType(), arg);
363 return RValue::get(call->getResult(0));
364}
365
366template <class Operation>
368 mlir::Value arg = cgf.emitScalarExpr(e.getArg(0));
369 auto call =
370 Operation::create(cgf.getBuilder(), arg.getLoc(), arg.getType(), arg);
371 return RValue::get(call->getResult(0));
372}
373
374template <typename Op>
376 const CallExpr &e) {
377 mlir::Type resultType = cgf.convertType(e.getType());
378 mlir::Value src = cgf.emitScalarExpr(e.getArg(0));
379
381
382 auto call = Op::create(cgf.getBuilder(), src.getLoc(), resultType, src);
383 return RValue::get(call->getResult(0));
384}
385
386template <typename Op>
388 mlir::Value arg0 = cgf.emitScalarExpr(e.getArg(0));
389 mlir::Value arg1 = cgf.emitScalarExpr(e.getArg(1));
390
391 mlir::Location loc = cgf.getLoc(e.getExprLoc());
392 mlir::Type ty = cgf.convertType(e.getType());
393 auto call = Op::create(cgf.getBuilder(), loc, ty, arg0, arg1);
394
395 return RValue::get(call->getResult(0));
396}
397
398template <typename Op>
400 const CallExpr &e) {
401 mlir::Value arg0 = cgf.emitScalarExpr(e.getArg(0));
402 mlir::Value arg1 = cgf.emitScalarExpr(e.getArg(1));
403 mlir::Value arg2 = cgf.emitScalarExpr(e.getArg(2));
404
405 mlir::Location loc = cgf.getLoc(e.getExprLoc());
406 mlir::Type ty = cgf.convertType(e.getType());
407
409
410 auto call = Op::create(cgf.getBuilder(), loc, ty, arg0, arg1, arg2);
411 return RValue::get(call->getResult(0));
412}
413
414template <typename Op>
416 const CallExpr &e) {
417 mlir::Value arg0 = cgf.emitScalarExpr(e.getArg(0));
418 mlir::Value arg1 = cgf.emitScalarExpr(e.getArg(1));
419
420 mlir::Location loc = cgf.getLoc(e.getExprLoc());
421 mlir::Type ty = cgf.convertType(e.getType());
422
424
425 auto call = Op::create(cgf.getBuilder(), loc, ty, arg0, arg1);
426 return call->getResult(0);
427}
428
430 unsigned builtinID) {
431
432 if (cgf.getContext().BuiltinInfo.isLibFunction(builtinID)) {
433 cgf.cgm.errorNYI(
434 e->getSourceRange(),
435 std::string("unimplemented X86 library function builtin call: ") +
436 cgf.getContext().BuiltinInfo.getName(builtinID));
437 } else {
438 cgf.cgm.errorNYI(e->getSourceRange(),
439 std::string("unimplemented X86 builtin call: ") +
440 cgf.getContext().BuiltinInfo.getName(builtinID));
441 }
442
443 return cgf.getUndefRValue(e->getType());
444}
445
447 unsigned builtinID) {
448 assert(builtinID == Builtin::BI__builtin_alloca ||
449 builtinID == Builtin::BI__builtin_alloca_uninitialized ||
450 builtinID == Builtin::BIalloca || builtinID == Builtin::BI_alloca);
451
452 // Get alloca size input
453 mlir::Value size = cgf.emitScalarExpr(e->getArg(0));
454
455 // The alignment of the alloca should correspond to __BIGGEST_ALIGNMENT__.
456 const TargetInfo &ti = cgf.getContext().getTargetInfo();
457 const CharUnits suitableAlignmentInBytes =
459
460 // Emit the alloca op with type `u8 *` to match the semantics of
461 // `llvm.alloca`. We later bitcast the type to `void *` to match the
462 // semantics of C/C++
463 // FIXME(cir): It may make sense to allow AllocaOp of type `u8` to return a
464 // pointer of type `void *`. This will require a change to the allocaOp
465 // verifier.
466 CIRGenBuilderTy &builder = cgf.getBuilder();
467 mlir::Value allocaAddr = builder.createAlloca(
468 cgf.getLoc(e->getSourceRange()), builder.getUInt8PtrTy(),
469 builder.getUInt8Ty(), "bi_alloca", suitableAlignmentInBytes, size);
470
471 // Initialize the allocated buffer if required.
472 if (builtinID != Builtin::BI__builtin_alloca_uninitialized) {
473 // Initialize the alloca with the given size and alignment according to
474 // the lang opts. Only the trivial non-initialization is supported for
475 // now.
476
477 switch (cgf.getLangOpts().getTrivialAutoVarInit()) {
479 // Nothing to initialize.
480 break;
483 cgf.cgm.errorNYI("trivial auto var init");
484 break;
485 }
486 }
487
488 // An alloca will always return a pointer to the alloca (stack) address
489 // space. This address space need not be the same as the AST / Language
490 // default (e.g. in C / C++ auto vars are in the generic address space). At
491 // the AST level this is handled within CreateTempAlloca et al., but for the
492 // builtin / dynamic alloca we have to handle it here.
493
497 cgf.cgm.errorNYI(e->getSourceRange(),
498 "Address Space Cast for builtin alloca");
499 }
500
501 // Bitcast the alloca to the expected type.
502 return RValue::get(builder.createBitcast(
503 allocaAddr, builder.getVoidPtrTy(cgf.getCIRAllocaAddressSpace())));
504}
505
507 unsigned builtinID) {
508 std::optional<bool> errnoOverriden;
509 // ErrnoOverriden is true if math-errno is overriden via the
510 // '#pragma float_control(precise, on)'. This pragma disables fast-math,
511 // which implies math-errno.
512 if (e->hasStoredFPFeatures()) {
514 if (op.hasMathErrnoOverride())
515 errnoOverriden = op.getMathErrnoOverride();
516 }
517 // True if 'attribute__((optnone))' is used. This attribute overrides
518 // fast-math which implies math-errno.
519 bool optNone =
520 cgf.curFuncDecl && cgf.curFuncDecl->hasAttr<OptimizeNoneAttr>();
521 bool isOptimizationEnabled = cgf.cgm.getCodeGenOpts().OptimizationLevel != 0;
522 bool generateFPMathIntrinsics =
524 builtinID, cgf.cgm.getTriple(), errnoOverriden,
525 cgf.getLangOpts().MathErrno, optNone, isOptimizationEnabled);
526 return generateFPMathIntrinsics;
527}
528
530 unsigned builtinID) {
532 switch (builtinID) {
533 case Builtin::BIacos:
534 case Builtin::BIacosf:
535 case Builtin::BIacosl:
536 case Builtin::BI__builtin_acos:
537 case Builtin::BI__builtin_acosf:
538 case Builtin::BI__builtin_acosf16:
539 case Builtin::BI__builtin_acosl:
540 case Builtin::BI__builtin_acosf128:
541 case Builtin::BI__builtin_elementwise_acos:
543 case Builtin::BIasin:
544 case Builtin::BIasinf:
545 case Builtin::BIasinl:
546 case Builtin::BI__builtin_asin:
547 case Builtin::BI__builtin_asinf:
548 case Builtin::BI__builtin_asinf16:
549 case Builtin::BI__builtin_asinl:
550 case Builtin::BI__builtin_asinf128:
551 case Builtin::BI__builtin_elementwise_asin:
553 case Builtin::BIatan:
554 case Builtin::BIatanf:
555 case Builtin::BIatanl:
556 case Builtin::BI__builtin_atan:
557 case Builtin::BI__builtin_atanf:
558 case Builtin::BI__builtin_atanf16:
559 case Builtin::BI__builtin_atanl:
560 case Builtin::BI__builtin_atanf128:
561 case Builtin::BI__builtin_elementwise_atan:
563 case Builtin::BIatan2:
564 case Builtin::BIatan2f:
565 case Builtin::BIatan2l:
566 case Builtin::BI__builtin_atan2:
567 case Builtin::BI__builtin_atan2f:
568 case Builtin::BI__builtin_atan2f16:
569 case Builtin::BI__builtin_atan2l:
570 case Builtin::BI__builtin_atan2f128:
571 case Builtin::BI__builtin_elementwise_atan2:
572 return RValue::get(
574 case Builtin::BIceil:
575 case Builtin::BIceilf:
576 case Builtin::BIceill:
577 case Builtin::BI__builtin_ceil:
578 case Builtin::BI__builtin_ceilf:
579 case Builtin::BI__builtin_ceilf16:
580 case Builtin::BI__builtin_ceill:
581 case Builtin::BI__builtin_ceilf128:
582 case Builtin::BI__builtin_elementwise_ceil:
584 case Builtin::BIcopysign:
585 case Builtin::BIcopysignf:
586 case Builtin::BIcopysignl:
587 case Builtin::BI__builtin_copysign:
588 case Builtin::BI__builtin_copysignf:
589 case Builtin::BI__builtin_copysignf16:
590 case Builtin::BI__builtin_copysignl:
591 case Builtin::BI__builtin_copysignf128:
593 case Builtin::BIcos:
594 case Builtin::BIcosf:
595 case Builtin::BIcosl:
596 case Builtin::BI__builtin_cos:
597 case Builtin::BI__builtin_cosf:
598 case Builtin::BI__builtin_cosf16:
599 case Builtin::BI__builtin_cosl:
600 case Builtin::BI__builtin_cosf128:
601 case Builtin::BI__builtin_elementwise_cos:
603 case Builtin::BIcosh:
604 case Builtin::BIcoshf:
605 case Builtin::BIcoshl:
606 case Builtin::BI__builtin_cosh:
607 case Builtin::BI__builtin_coshf:
608 case Builtin::BI__builtin_coshf16:
609 case Builtin::BI__builtin_coshl:
610 case Builtin::BI__builtin_coshf128:
611 case Builtin::BI__builtin_elementwise_cosh:
612 return errorBuiltinNYI(cgf, e, builtinID);
613 case Builtin::BIexp:
614 case Builtin::BIexpf:
615 case Builtin::BIexpl:
616 case Builtin::BI__builtin_exp:
617 case Builtin::BI__builtin_expf:
618 case Builtin::BI__builtin_expf16:
619 case Builtin::BI__builtin_expl:
620 case Builtin::BI__builtin_expf128:
621 case Builtin::BI__builtin_elementwise_exp:
623 case Builtin::BIexp2:
624 case Builtin::BIexp2f:
625 case Builtin::BIexp2l:
626 case Builtin::BI__builtin_exp2:
627 case Builtin::BI__builtin_exp2f:
628 case Builtin::BI__builtin_exp2f16:
629 case Builtin::BI__builtin_exp2l:
630 case Builtin::BI__builtin_exp2f128:
631 case Builtin::BI__builtin_elementwise_exp2:
633 case Builtin::BI__builtin_exp10:
634 case Builtin::BI__builtin_exp10f:
635 case Builtin::BI__builtin_exp10f16:
636 case Builtin::BI__builtin_exp10l:
637 case Builtin::BI__builtin_exp10f128:
638 case Builtin::BI__builtin_elementwise_exp10:
639 return errorBuiltinNYI(cgf, e, builtinID);
640 case Builtin::BIfabs:
641 case Builtin::BIfabsf:
642 case Builtin::BIfabsl:
643 case Builtin::BI__builtin_fabs:
644 case Builtin::BI__builtin_fabsf:
645 case Builtin::BI__builtin_fabsf16:
646 case Builtin::BI__builtin_fabsl:
647 case Builtin::BI__builtin_fabsf128:
649 case Builtin::BIfloor:
650 case Builtin::BIfloorf:
651 case Builtin::BIfloorl:
652 case Builtin::BI__builtin_floor:
653 case Builtin::BI__builtin_floorf:
654 case Builtin::BI__builtin_floorf16:
655 case Builtin::BI__builtin_floorl:
656 case Builtin::BI__builtin_floorf128:
657 case Builtin::BI__builtin_elementwise_floor:
659 case Builtin::BIfma:
660 case Builtin::BIfmaf:
661 case Builtin::BIfmal:
662 case Builtin::BI__builtin_fma:
663 case Builtin::BI__builtin_fmaf:
664 case Builtin::BI__builtin_fmaf16:
665 case Builtin::BI__builtin_fmal:
666 case Builtin::BI__builtin_fmaf128:
667 case Builtin::BI__builtin_elementwise_fma:
669 case Builtin::BIfmax:
670 case Builtin::BIfmaxf:
671 case Builtin::BIfmaxl:
672 case Builtin::BI__builtin_fmax:
673 case Builtin::BI__builtin_fmaxf:
674 case Builtin::BI__builtin_fmaxf16:
675 case Builtin::BI__builtin_fmaxl:
676 case Builtin::BI__builtin_fmaxf128:
677 return RValue::get(
679 case Builtin::BIfmin:
680 case Builtin::BIfminf:
681 case Builtin::BIfminl:
682 case Builtin::BI__builtin_fmin:
683 case Builtin::BI__builtin_fminf:
684 case Builtin::BI__builtin_fminf16:
685 case Builtin::BI__builtin_fminl:
686 case Builtin::BI__builtin_fminf128:
687 return RValue::get(
689 case Builtin::BIfmaximum_num:
690 case Builtin::BIfmaximum_numf:
691 case Builtin::BIfmaximum_numl:
692 case Builtin::BI__builtin_fmaximum_num:
693 case Builtin::BI__builtin_fmaximum_numf:
694 case Builtin::BI__builtin_fmaximum_numf16:
695 case Builtin::BI__builtin_fmaximum_numl:
696 case Builtin::BI__builtin_fmaximum_numf128:
697 case Builtin::BIfminimum_num:
698 case Builtin::BIfminimum_numf:
699 case Builtin::BIfminimum_numl:
700 case Builtin::BI__builtin_fminimum_num:
701 case Builtin::BI__builtin_fminimum_numf:
702 case Builtin::BI__builtin_fminimum_numf16:
703 case Builtin::BI__builtin_fminimum_numl:
704 case Builtin::BI__builtin_fminimum_numf128:
705 return errorBuiltinNYI(cgf, e, builtinID);
706 case Builtin::BIfmod:
707 case Builtin::BIfmodf:
708 case Builtin::BIfmodl:
709 case Builtin::BI__builtin_fmod:
710 case Builtin::BI__builtin_fmodf:
711 case Builtin::BI__builtin_fmodf16:
712 case Builtin::BI__builtin_fmodl:
713 case Builtin::BI__builtin_fmodf128:
714 case Builtin::BI__builtin_elementwise_fmod:
715 return RValue::get(
717 case Builtin::BIlog:
718 case Builtin::BIlogf:
719 case Builtin::BIlogl:
720 case Builtin::BI__builtin_log:
721 case Builtin::BI__builtin_logf:
722 case Builtin::BI__builtin_logf16:
723 case Builtin::BI__builtin_logl:
724 case Builtin::BI__builtin_logf128:
725 case Builtin::BI__builtin_elementwise_log:
727 case Builtin::BIlog10:
728 case Builtin::BIlog10f:
729 case Builtin::BIlog10l:
730 case Builtin::BI__builtin_log10:
731 case Builtin::BI__builtin_log10f:
732 case Builtin::BI__builtin_log10f16:
733 case Builtin::BI__builtin_log10l:
734 case Builtin::BI__builtin_log10f128:
735 case Builtin::BI__builtin_elementwise_log10:
737 case Builtin::BIlog2:
738 case Builtin::BIlog2f:
739 case Builtin::BIlog2l:
740 case Builtin::BI__builtin_log2:
741 case Builtin::BI__builtin_log2f:
742 case Builtin::BI__builtin_log2f16:
743 case Builtin::BI__builtin_log2l:
744 case Builtin::BI__builtin_log2f128:
745 case Builtin::BI__builtin_elementwise_log2:
747 case Builtin::BInearbyint:
748 case Builtin::BInearbyintf:
749 case Builtin::BInearbyintl:
750 case Builtin::BI__builtin_nearbyint:
751 case Builtin::BI__builtin_nearbyintf:
752 case Builtin::BI__builtin_nearbyintl:
753 case Builtin::BI__builtin_nearbyintf128:
754 case Builtin::BI__builtin_elementwise_nearbyint:
756 case Builtin::BIpow:
757 case Builtin::BIpowf:
758 case Builtin::BIpowl:
759 case Builtin::BI__builtin_pow:
760 case Builtin::BI__builtin_powf:
761 case Builtin::BI__builtin_powf16:
762 case Builtin::BI__builtin_powl:
763 case Builtin::BI__builtin_powf128:
764 return RValue::get(
766 case Builtin::BI__builtin_elementwise_pow:
767 return errorBuiltinNYI(cgf, e, builtinID);
768 case Builtin::BIrint:
769 case Builtin::BIrintf:
770 case Builtin::BIrintl:
771 case Builtin::BI__builtin_rint:
772 case Builtin::BI__builtin_rintf:
773 case Builtin::BI__builtin_rintf16:
774 case Builtin::BI__builtin_rintl:
775 case Builtin::BI__builtin_rintf128:
776 case Builtin::BI__builtin_elementwise_rint:
778 case Builtin::BIround:
779 case Builtin::BIroundf:
780 case Builtin::BIroundl:
781 case Builtin::BI__builtin_round:
782 case Builtin::BI__builtin_roundf:
783 case Builtin::BI__builtin_roundf16:
784 case Builtin::BI__builtin_roundl:
785 case Builtin::BI__builtin_roundf128:
786 case Builtin::BI__builtin_elementwise_round:
788 case Builtin::BIroundeven:
789 case Builtin::BIroundevenf:
790 case Builtin::BIroundevenl:
791 case Builtin::BI__builtin_roundeven:
792 case Builtin::BI__builtin_roundevenf:
793 case Builtin::BI__builtin_roundevenf16:
794 case Builtin::BI__builtin_roundevenl:
795 case Builtin::BI__builtin_roundevenf128:
796 case Builtin::BI__builtin_elementwise_roundeven:
798 case Builtin::BIsin:
799 case Builtin::BIsinf:
800 case Builtin::BIsinl:
801 case Builtin::BI__builtin_sin:
802 case Builtin::BI__builtin_sinf:
803 case Builtin::BI__builtin_sinf16:
804 case Builtin::BI__builtin_sinl:
805 case Builtin::BI__builtin_sinf128:
806 case Builtin::BI__builtin_elementwise_sin:
808 case Builtin::BIsinh:
809 case Builtin::BIsinhf:
810 case Builtin::BIsinhl:
811 case Builtin::BI__builtin_sinh:
812 case Builtin::BI__builtin_sinhf:
813 case Builtin::BI__builtin_sinhf16:
814 case Builtin::BI__builtin_sinhl:
815 case Builtin::BI__builtin_sinhf128:
816 case Builtin::BI__builtin_elementwise_sinh:
817 case Builtin::BI__builtin_sincospi:
818 case Builtin::BI__builtin_sincospif:
819 case Builtin::BI__builtin_sincospil:
820 case Builtin::BIsincos:
821 case Builtin::BIsincosf:
822 case Builtin::BIsincosl:
823 case Builtin::BI__builtin_sincos:
824 case Builtin::BI__builtin_sincosf:
825 case Builtin::BI__builtin_sincosf16:
826 case Builtin::BI__builtin_sincosl:
827 case Builtin::BI__builtin_sincosf128:
828 return errorBuiltinNYI(cgf, e, builtinID);
829 case Builtin::BIsqrt:
830 case Builtin::BIsqrtf:
831 case Builtin::BIsqrtl:
832 case Builtin::BI__builtin_sqrt:
833 case Builtin::BI__builtin_sqrtf:
834 case Builtin::BI__builtin_sqrtf16:
835 case Builtin::BI__builtin_sqrtl:
836 case Builtin::BI__builtin_sqrtf128:
837 case Builtin::BI__builtin_elementwise_sqrt:
839 case Builtin::BItan:
840 case Builtin::BItanf:
841 case Builtin::BItanl:
842 case Builtin::BI__builtin_tan:
843 case Builtin::BI__builtin_tanf:
844 case Builtin::BI__builtin_tanf16:
845 case Builtin::BI__builtin_tanl:
846 case Builtin::BI__builtin_tanf128:
847 case Builtin::BI__builtin_elementwise_tan:
849 case Builtin::BItanh:
850 case Builtin::BItanhf:
851 case Builtin::BItanhl:
852 case Builtin::BI__builtin_tanh:
853 case Builtin::BI__builtin_tanhf:
854 case Builtin::BI__builtin_tanhf16:
855 case Builtin::BI__builtin_tanhl:
856 case Builtin::BI__builtin_tanhf128:
857 case Builtin::BI__builtin_elementwise_tanh:
858 return errorBuiltinNYI(cgf, e, builtinID);
859 case Builtin::BItrunc:
860 case Builtin::BItruncf:
861 case Builtin::BItruncl:
862 case Builtin::BI__builtin_trunc:
863 case Builtin::BI__builtin_truncf:
864 case Builtin::BI__builtin_truncf16:
865 case Builtin::BI__builtin_truncl:
866 case Builtin::BI__builtin_truncf128:
867 case Builtin::BI__builtin_elementwise_trunc:
869 case Builtin::BIlround:
870 case Builtin::BIlroundf:
871 case Builtin::BIlroundl:
872 case Builtin::BI__builtin_lround:
873 case Builtin::BI__builtin_lroundf:
874 case Builtin::BI__builtin_lroundl:
875 case Builtin::BI__builtin_lroundf128:
877 case Builtin::BIllround:
878 case Builtin::BIllroundf:
879 case Builtin::BIllroundl:
880 case Builtin::BI__builtin_llround:
881 case Builtin::BI__builtin_llroundf:
882 case Builtin::BI__builtin_llroundl:
883 case Builtin::BI__builtin_llroundf128:
885 case Builtin::BIlrint:
886 case Builtin::BIlrintf:
887 case Builtin::BIlrintl:
888 case Builtin::BI__builtin_lrint:
889 case Builtin::BI__builtin_lrintf:
890 case Builtin::BI__builtin_lrintl:
891 case Builtin::BI__builtin_lrintf128:
893 case Builtin::BIllrint:
894 case Builtin::BIllrintf:
895 case Builtin::BIllrintl:
896 case Builtin::BI__builtin_llrint:
897 case Builtin::BI__builtin_llrintf:
898 case Builtin::BI__builtin_llrintl:
899 case Builtin::BI__builtin_llrintf128:
901 case Builtin::BI__builtin_ldexp:
902 case Builtin::BI__builtin_ldexpf:
903 case Builtin::BI__builtin_ldexpl:
904 case Builtin::BI__builtin_ldexpf16:
905 case Builtin::BI__builtin_ldexpf128:
906 case Builtin::BI__builtin_elementwise_ldexp:
907 return errorBuiltinNYI(cgf, e, builtinID);
908 default:
909 break;
910 }
911
912 return RValue::getIgnored();
913}
914
915// FIXME: Remove cgf parameter when all descriptor kinds are implemented
916static mlir::Type
919 mlir::MLIRContext *context) {
920 using namespace llvm::Intrinsic;
921
922 IITDescriptor descriptor = infos.front();
923 infos = infos.slice(1);
924
925 switch (descriptor.Kind) {
926 case IITDescriptor::Void:
927 return cir::VoidType::get(context);
928 case IITDescriptor::Half:
929 return cir::FP16Type::get(context);
930 case IITDescriptor::BFloat:
931 return cir::BF16Type::get(context);
932 case IITDescriptor::Float:
933 return cir::SingleType::get(context);
934 case IITDescriptor::Double:
935 return cir::DoubleType::get(context);
936 case IITDescriptor::Quad:
937 return cir::FP128Type::get(context);
938 // If the intrinsic expects unsigned integers, the signedness is corrected in
939 // correctIntegerSignedness()
940 case IITDescriptor::Integer:
941 return cir::IntType::get(context, descriptor.IntegerWidth,
942 /*isSigned=*/true);
943 case IITDescriptor::Vector: {
944 mlir::Type elementType = decodeFixedType(cgf, infos, context);
945 unsigned numElements = descriptor.VectorWidth.getFixedValue();
946 return cir::VectorType::get(elementType, numElements);
947 }
948 case IITDescriptor::Pointer: {
949 mlir::Builder builder(context);
950 auto addrSpace = cir::TargetAddressSpaceAttr::get(
951 context, descriptor.PointerAddressSpace);
952 return cir::PointerType::get(cir::VoidType::get(context), addrSpace);
953 }
954 default:
955 cgf.cgm.errorNYI("Unimplemented intrinsic type descriptor");
956 return cir::VoidType::get(context);
957 }
958}
959
960/// Helper function to correct integer signedness for intrinsic arguments and
961/// return type. IIT always returns signed integers, but the actual intrinsic
962/// may expect unsigned integers based on the AST FunctionDecl parameter types.
963static mlir::Type correctIntegerSignedness(mlir::Type iitType, QualType astType,
964 mlir::MLIRContext *context) {
965 auto intTy = dyn_cast<cir::IntType>(iitType);
966 if (!intTy)
967 return iitType;
968
969 if (astType->isUnsignedIntegerType())
970 return cir::IntType::get(context, intTy.getWidth(), /*isSigned=*/false);
971
972 return iitType;
973}
974
975static mlir::Value getCorrectedPtr(mlir::Value argValue, mlir::Type expectedTy,
976 CIRGenBuilderTy &builder) {
977 auto ptrType = mlir::cast<cir::PointerType>(argValue.getType());
978
979 auto expectedPtrType = mlir::cast<cir::PointerType>(expectedTy);
980 assert(ptrType != expectedPtrType && "types should not match");
981
982 if (ptrType.getAddrSpace() != expectedPtrType.getAddrSpace()) {
984 "address space handling not yet implemented");
985 auto newPtrType = cir::PointerType::get(ptrType.getPointee(),
986 expectedPtrType.getAddrSpace());
987 return builder.createAddrSpaceCast(argValue, newPtrType);
988 }
989
990 return builder.createBitcast(argValue, expectedTy);
991}
992
993static cir::FuncType getIntrinsicType(CIRGenFunction &cgf,
994 mlir::MLIRContext *context,
995 llvm::Intrinsic::ID id) {
996 using namespace llvm::Intrinsic;
997
999 auto [tableRef, _, isVarArg] = getIntrinsicInfoTableEntries(id, table);
1000
1001 mlir::Type resultTy = decodeFixedType(cgf, tableRef, context);
1002
1004 while (!tableRef.empty())
1005 argTypes.push_back(decodeFixedType(cgf, tableRef, context));
1006
1007 // CIR convention: no explicit void return type
1008 if (isa<cir::VoidType>(resultTy))
1009 return cir::FuncType::get(context, argTypes, /*optionalReturnType=*/nullptr,
1010 isVarArg);
1011
1012 return cir::FuncType::get(context, argTypes, resultTy, isVarArg);
1013}
1014
1016 const CallExpr *e,
1018 mlir::Location loc = getLoc(e->getSourceRange());
1019
1020 // See if we can constant fold this builtin. If so, don't emit it at all.
1021 // TODO: Extend this handling to all builtin calls that we can constant-fold.
1022 // Do not constant-fold immediate (target-specific) builtins; their ASTs can
1023 // trigger the constant evaluator in cases it cannot safely handle.
1024 // Skip EvaluateAsRValue for those.
1025 Expr::EvalResult result;
1026 if (e->isPRValue() && !getContext().BuiltinInfo.isImmediate(builtinID) &&
1027 e->EvaluateAsRValue(result, cgm.getASTContext()) &&
1028 !result.hasSideEffects()) {
1029 if (result.Val.isInt()) {
1030 QualType type = e->getType();
1031 if (type->isBooleanType())
1032 return RValue::get(
1033 builder.getBool(result.Val.getInt().getBoolValue(), loc));
1034 return RValue::get(builder.getConstInt(loc, result.Val.getInt()));
1035 }
1036 if (result.Val.isFloat()) {
1037 // Note: we are using result type of CallExpr to determine the type of
1038 // the constant. Classic codegen uses the result value to determine the
1039 // type. We feel it should be Ok to use expression type because it is
1040 // hard to imagine a builtin function evaluates to a value that
1041 // over/underflows its own defined type.
1042 mlir::Type type = convertType(e->getType());
1043 return RValue::get(builder.getConstFP(loc, type, result.Val.getFloat()));
1044 }
1045 }
1046
1047 const FunctionDecl *fd = gd.getDecl()->getAsFunction();
1048
1050
1051 // If the builtin has been declared explicitly with an assembler label,
1052 // disable the specialized emitting below. Ideally we should communicate the
1053 // rename in IR, or at least avoid generating the intrinsic calls that are
1054 // likely to get lowered to the renamed library functions.
1055 unsigned builtinIDIfNoAsmLabel = fd->hasAttr<AsmLabelAttr>() ? 0 : builtinID;
1056
1057 bool generateFPMathIntrinsics =
1058 shouldCIREmitFPMathIntrinsic(*this, e, builtinID);
1059
1060 if (generateFPMathIntrinsics) {
1061 // Try to match the builtinID with a floating point math builtin.
1062 RValue rv = tryEmitFPMathIntrinsic(*this, e, builtinIDIfNoAsmLabel);
1063
1064 // Return the result directly if a math intrinsic was generated.
1065 if (!rv.isIgnored()) {
1066 return rv;
1067 }
1068 }
1069
1071
1072 switch (builtinIDIfNoAsmLabel) {
1073 default:
1074 break;
1075
1076 // C stdarg builtins.
1077 case Builtin::BI__builtin_stdarg_start:
1078 case Builtin::BI__builtin_va_start:
1079 case Builtin::BI__builtin_c23_va_start:
1080 case Builtin::BI__va_start: {
1081 mlir::Value vaList = builtinID == Builtin::BI__va_start
1082 ? emitScalarExpr(e->getArg(0))
1083 : emitVAListRef(e->getArg(0)).getPointer();
1084 emitVAStart(vaList);
1085 return {};
1086 }
1087
1088 case Builtin::BI__builtin_va_end:
1090 return {};
1091 case Builtin::BI__builtin_va_copy: {
1092 mlir::Value dstPtr = emitVAListRef(e->getArg(0)).getPointer();
1093 mlir::Value srcPtr = emitVAListRef(e->getArg(1)).getPointer();
1094 cir::VACopyOp::create(builder, dstPtr.getLoc(), dstPtr, srcPtr);
1095 return {};
1096 }
1097
1098 case Builtin::BIabs:
1099 case Builtin::BIlabs:
1100 case Builtin::BIllabs:
1101 case Builtin::BI__builtin_abs:
1102 case Builtin::BI__builtin_labs:
1103 case Builtin::BI__builtin_llabs: {
1104 bool sanitizeOverflow = sanOpts.has(SanitizerKind::SignedIntegerOverflow);
1105 mlir::Value arg = emitScalarExpr(e->getArg(0));
1106 mlir::Value result;
1107 switch (getLangOpts().getSignedOverflowBehavior()) {
1109 result = cir::AbsOp::create(builder, loc, arg.getType(), arg,
1110 /*minIsPoison=*/false);
1111 break;
1113 if (!sanitizeOverflow) {
1114 result = cir::AbsOp::create(builder, loc, arg.getType(), arg,
1115 /*minIsPoison=*/true);
1116 break;
1117 }
1118 [[fallthrough]];
1120 cgm.errorNYI(e->getSourceRange(), "abs with overflow handling");
1121 return RValue::get(nullptr);
1122 }
1123 return RValue::get(result);
1124 }
1125
1126 case Builtin::BI__assume:
1127 case Builtin::BI__builtin_assume: {
1128 if (e->getArg(0)->HasSideEffects(getContext()))
1129 return RValue::get(nullptr);
1130
1131 mlir::Value argValue = emitCheckedArgForAssume(e->getArg(0));
1132 cir::AssumeOp::create(builder, loc, argValue, cir::AssumeBundleKind::None,
1133 mlir::ValueRange{});
1134 return RValue::get(nullptr);
1135 }
1136
1137 case Builtin::BI__builtin_assume_separate_storage: {
1138 mlir::Value value0 = emitScalarExpr(e->getArg(0));
1139 mlir::Value value1 = emitScalarExpr(e->getArg(1));
1140 mlir::Value cond = builder.getBool(true, loc);
1141 cir::AssumeOp::create(builder, loc, cond,
1142 cir::AssumeBundleKind::SeparateStorage,
1143 mlir::ValueRange{value0, value1});
1144 return RValue::get(nullptr);
1145 }
1146
1147 case Builtin::BI__builtin_assume_dereferenceable: {
1148 mlir::Value ptrValue = emitScalarExpr(e->getArg(0));
1149 mlir::Value sizeValue = emitScalarExpr(e->getArg(1));
1150 // The `dereferenceable` operand bundle expects a pointer-sized unsigned
1151 // integer; widen/narrow as needed.
1152 mlir::Type uintPtrTy = convertType(getContext().getUIntPtrType());
1153 if (sizeValue.getType() != uintPtrTy)
1154 sizeValue = builder.createIntCast(sizeValue, uintPtrTy);
1155 mlir::Value cond = builder.getBool(true, loc);
1156 cir::AssumeOp::create(builder, loc, cond,
1157 cir::AssumeBundleKind::Dereferenceable,
1158 mlir::ValueRange{ptrValue, sizeValue});
1159 return RValue::get(nullptr);
1160 }
1161
1162 case Builtin::BI__builtin_assume_aligned: {
1163 const Expr *ptrExpr = e->getArg(0);
1164 mlir::Value ptrValue = emitScalarExpr(ptrExpr);
1165 mlir::Value offsetValue =
1166 (e->getNumArgs() > 2) ? emitScalarExpr(e->getArg(2)) : nullptr;
1167
1168 std::optional<llvm::APSInt> alignment =
1170 assert(alignment.has_value() &&
1171 "the second argument to __builtin_assume_aligned must be an "
1172 "integral constant expression");
1173
1174 mlir::Value result =
1175 emitAlignmentAssumption(ptrValue, ptrExpr, ptrExpr->getExprLoc(),
1176 alignment->getSExtValue(), offsetValue);
1177 return RValue::get(result);
1178 }
1179
1180 case Builtin::BI__builtin_complex: {
1181 mlir::Value real = emitScalarExpr(e->getArg(0));
1182 mlir::Value imag = emitScalarExpr(e->getArg(1));
1183 mlir::Value complex = builder.createComplexCreate(loc, real, imag);
1184 return RValue::getComplex(complex);
1185 }
1186
1187 case Builtin::BI__builtin_creal:
1188 case Builtin::BI__builtin_crealf:
1189 case Builtin::BI__builtin_creall:
1190 case Builtin::BIcreal:
1191 case Builtin::BIcrealf:
1192 case Builtin::BIcreall: {
1193 mlir::Value complex = emitComplexExpr(e->getArg(0));
1194 mlir::Value real = builder.createComplexReal(loc, complex);
1195 return RValue::get(real);
1196 }
1197
1198 case Builtin::BI__builtin_cimag:
1199 case Builtin::BI__builtin_cimagf:
1200 case Builtin::BI__builtin_cimagl:
1201 case Builtin::BIcimag:
1202 case Builtin::BIcimagf:
1203 case Builtin::BIcimagl: {
1204 mlir::Value complex = emitComplexExpr(e->getArg(0));
1205 mlir::Value imag = builder.createComplexImag(loc, complex);
1206 return RValue::get(imag);
1207 }
1208
1209 case Builtin::BI__builtin_conj:
1210 case Builtin::BI__builtin_conjf:
1211 case Builtin::BI__builtin_conjl:
1212 case Builtin::BIconj:
1213 case Builtin::BIconjf:
1214 case Builtin::BIconjl: {
1215 mlir::Value complex = emitComplexExpr(e->getArg(0));
1216 mlir::Value conj = builder.createComplexConj(loc, complex);
1217 return RValue::getComplex(conj);
1218 }
1219
1220 case Builtin::BI__builtin_clrsb:
1221 case Builtin::BI__builtin_clrsbl:
1222 case Builtin::BI__builtin_clrsbll:
1223 return emitBuiltinBitOp<cir::BitClrsbOp>(*this, e);
1224
1225 case Builtin::BI__builtin_ctzs:
1226 case Builtin::BI__builtin_ctz:
1227 case Builtin::BI__builtin_ctzl:
1228 case Builtin::BI__builtin_ctzll:
1230 return emitBuiltinBitOp<cir::BitCtzOp>(*this, e,
1231 getTarget().isCLZForZeroUndef());
1232 case Builtin::BI__builtin_ctzg:
1234
1235 case Builtin::BI__builtin_clzs:
1236 case Builtin::BI__builtin_clz:
1237 case Builtin::BI__builtin_clzl:
1238 case Builtin::BI__builtin_clzll:
1240 return emitBuiltinBitOp<cir::BitClzOp>(*this, e,
1241 getTarget().isCLZForZeroUndef());
1242 case Builtin::BI__builtin_clzg:
1244
1245 case Builtin::BI__builtin_elementwise_ctzg:
1246 cgm.errorNYI(e->getSourceRange(), "__builtin_elementwise_ctzg");
1247 return RValue::get(nullptr);
1248 case Builtin::BI__builtin_elementwise_clzg:
1249 cgm.errorNYI(e->getSourceRange(), "__builtin_elementwise_clzg");
1250 return RValue::get(nullptr);
1251
1252 case Builtin::BI__builtin_ffs:
1253 case Builtin::BI__builtin_ffsl:
1254 case Builtin::BI__builtin_ffsll:
1255 return emitBuiltinBitOp<cir::BitFfsOp>(*this, e);
1256
1257 case Builtin::BI__builtin_parity:
1258 case Builtin::BI__builtin_parityl:
1259 case Builtin::BI__builtin_parityll:
1260 return emitBuiltinBitOp<cir::BitParityOp>(*this, e);
1261
1262 case Builtin::BI__lzcnt16:
1263 case Builtin::BI__lzcnt:
1264 case Builtin::BI__lzcnt64:
1265 return emitBuiltinBitOp<cir::BitClzOp>(*this, e);
1266
1267 case Builtin::BI__popcnt16:
1268 case Builtin::BI__popcnt:
1269 case Builtin::BI__popcnt64:
1270 case Builtin::BI__builtin_popcount:
1271 case Builtin::BI__builtin_popcountl:
1272 case Builtin::BI__builtin_popcountll:
1273 case Builtin::BI__builtin_popcountg:
1274 return emitBuiltinBitOp<cir::BitPopcountOp>(*this, e);
1275
1276 // Always return the argument of __builtin_unpredictable. LLVM does not
1277 // have an intrinsic corresponding to this builtin. Metadata for this
1278 // builtin should be added directly to instructions such as branches or
1279 // switches that use it.
1280 case Builtin::BI__builtin_unpredictable: {
1281 return RValue::get(emitScalarExpr(e->getArg(0)));
1282 }
1283
1284 case Builtin::BI__builtin_expect:
1285 case Builtin::BI__builtin_expect_with_probability: {
1286 mlir::Value argValue = emitScalarExpr(e->getArg(0));
1287 if (cgm.getCodeGenOpts().OptimizationLevel == 0)
1288 return RValue::get(argValue);
1289
1290 mlir::Value expectedValue = emitScalarExpr(e->getArg(1));
1291
1292 mlir::FloatAttr probAttr;
1293 if (builtinIDIfNoAsmLabel == Builtin::BI__builtin_expect_with_probability) {
1294 llvm::APFloat probability(0.0);
1295 const Expr *probArg = e->getArg(2);
1296 [[maybe_unused]] bool evalSucceeded =
1297 probArg->EvaluateAsFloat(probability, cgm.getASTContext());
1298 assert(evalSucceeded &&
1299 "probability should be able to evaluate as float");
1300 bool loseInfo = false; // ignored
1301 probability.convert(llvm::APFloat::IEEEdouble(),
1302 llvm::RoundingMode::Dynamic, &loseInfo);
1303 probAttr = mlir::FloatAttr::get(mlir::Float64Type::get(&getMLIRContext()),
1304 probability);
1305 }
1306
1307 auto result = cir::ExpectOp::create(builder, loc, argValue.getType(),
1308 argValue, expectedValue, probAttr);
1309 return RValue::get(result);
1310 }
1311
1312 case Builtin::BI__builtin_bswapg: {
1313 mlir::Value arg = emitScalarExpr(e->getArg(0));
1314 // CIR models bool as cir.bool rather than an integer, so peel it off
1315 // before the cast below. Like classic codegen's i1 case, it byte-swaps
1316 // to itself.
1317 if (mlir::isa<cir::BoolType>(arg.getType()))
1318 return RValue::get(arg);
1319 auto argTy = mlir::cast<cir::IntType>(arg.getType());
1320 // A single bit or a single byte byte-swaps to itself.
1321 if (argTy.getWidth() == 1 || argTy.getWidth() == 8)
1322 return RValue::get(arg);
1323 assert(argTy.getWidth() % 16 == 0 &&
1324 "__builtin_bswapg requires a single byte or a multiple of 16 bits");
1325 // cir.byte_swap requires an unsigned operand. Reinterpret a signed
1326 // argument as unsigned of the same width; createBuiltinBitOp casts the
1327 // swapped result back to the builtin's (possibly signed) return type.
1328 if (argTy.isSigned())
1329 arg = builder.createIntCast(arg, builder.getUIntNTy(argTy.getWidth()));
1330 return RValue::get(createBuiltinBitOp<cir::ByteSwapOp>(*this, e, arg));
1331 }
1332
1333 case Builtin::BI__builtin_bswap16:
1334 case Builtin::BI__builtin_bswap32:
1335 case Builtin::BI__builtin_bswap64:
1336 case Builtin::BI_byteswap_ushort:
1337 case Builtin::BI_byteswap_ulong:
1338 case Builtin::BI_byteswap_uint64: {
1339 mlir::Value arg = emitScalarExpr(e->getArg(0));
1340 return RValue::get(cir::ByteSwapOp::create(builder, loc, arg));
1341 }
1342
1343 case Builtin::BI__builtin_bitreverse8:
1344 case Builtin::BI__builtin_bitreverse16:
1345 case Builtin::BI__builtin_bitreverse32:
1346 case Builtin::BI__builtin_bitreverse64: {
1347 mlir::Value arg = emitScalarExpr(e->getArg(0));
1348 return RValue::get(cir::BitReverseOp::create(builder, loc, arg));
1349 }
1350
1351 case Builtin::BI__builtin_rotateleft8:
1352 case Builtin::BI__builtin_rotateleft16:
1353 case Builtin::BI__builtin_rotateleft32:
1354 case Builtin::BI__builtin_rotateleft64:
1355 return emitRotate(e, /*isRotateLeft=*/true);
1356
1357 case Builtin::BI__builtin_rotateright8:
1358 case Builtin::BI__builtin_rotateright16:
1359 case Builtin::BI__builtin_rotateright32:
1360 case Builtin::BI__builtin_rotateright64:
1361 return emitRotate(e, /*isRotateLeft=*/false);
1362
1363 case Builtin::BI__builtin_coro_id:
1364 case Builtin::BI__builtin_coro_promise:
1365 case Builtin::BI__builtin_coro_resume:
1366 case Builtin::BI__builtin_coro_noop:
1367 case Builtin::BI__builtin_coro_destroy:
1368 case Builtin::BI__builtin_coro_done:
1369 case Builtin::BI__builtin_coro_alloc:
1370 case Builtin::BI__builtin_coro_begin:
1371 case Builtin::BI__builtin_coro_end:
1372 case Builtin::BI__builtin_coro_suspend:
1373 case Builtin::BI__builtin_coro_align:
1374 cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_id like NYI");
1375 return getUndefRValue(e->getType());
1376
1377 case Builtin::BI__builtin_coro_frame: {
1378 return emitCoroutineFrame();
1379 }
1380 case Builtin::BI__builtin_coro_free:
1381 return RValue::get(emitCoroFreeBuiltin(e).getResult());
1382 case Builtin::BI__builtin_coro_size: {
1383 GlobalDecl gd{fd};
1384 mlir::Type ty = cgm.getTypes().getFunctionType(
1385 cgm.getTypes().arrangeGlobalDeclaration(gd));
1386 const auto *nd = cast<NamedDecl>(gd.getDecl());
1387 cir::FuncOp fnOp =
1388 cgm.getOrCreateCIRFunction(nd->getName(), ty, gd, /*ForVTable=*/false);
1389 fnOp.setBuiltin(true);
1390 return emitCall(e->getCallee()->getType(), CIRGenCallee::forDirect(fnOp), e,
1391 returnValue);
1392 }
1393
1394 case Builtin::BI__builtin_constant_p: {
1395 mlir::Type resultType = convertType(e->getType());
1396
1397 const Expr *arg = e->getArg(0);
1398 QualType argType = arg->getType();
1399 // FIXME: The allowance for Obj-C pointers and block pointers is historical
1400 // and likely a mistake.
1401 if (!argType->isIntegralOrEnumerationType() && !argType->isFloatingType() &&
1402 !argType->isObjCObjectPointerType() && !argType->isBlockPointerType()) {
1403 // Per the GCC documentation, only numeric constants are recognized after
1404 // inlining.
1405 return RValue::get(
1406 builder.getConstInt(getLoc(e->getSourceRange()),
1407 mlir::cast<cir::IntType>(resultType), 0));
1408 }
1409
1410 if (arg->HasSideEffects(getContext())) {
1411 // The argument is unevaluated, so be conservative if it might have
1412 // side-effects.
1413 return RValue::get(
1414 builder.getConstInt(getLoc(e->getSourceRange()),
1415 mlir::cast<cir::IntType>(resultType), 0));
1416 }
1417
1418 mlir::Value argValue = emitScalarExpr(arg);
1419 if (argType->isObjCObjectPointerType()) {
1420 cgm.errorNYI(e->getSourceRange(),
1421 "__builtin_constant_p: Obj-C object pointer");
1422 return {};
1423 }
1424 argValue = builder.createBitcast(argValue, convertType(argType));
1425
1426 mlir::Value result = cir::IsConstantOp::create(
1427 builder, getLoc(e->getSourceRange()), argValue);
1428 // IsConstantOp returns a bool, but __builtin_constant_p returns an int.
1429 result = builder.createBoolToInt(result, resultType);
1430 return RValue::get(result);
1431 }
1432 case Builtin::BI__builtin_dynamic_object_size:
1433 case Builtin::BI__builtin_object_size: {
1434 unsigned type =
1435 e->getArg(1)->EvaluateKnownConstInt(getContext()).getZExtValue();
1436 auto resType = mlir::cast<cir::IntType>(convertType(e->getType()));
1437
1438 // We pass this builtin onto the optimizer so that it can figure out the
1439 // object size in more complex cases.
1440 bool isDynamic = builtinID == Builtin::BI__builtin_dynamic_object_size;
1441 return RValue::get(emitBuiltinObjectSize(e->getArg(0), type, resType,
1442 /*EmittedE=*/nullptr, isDynamic));
1443 }
1444
1445 case Builtin::BI__builtin_prefetch: {
1446 auto evaluateOperandAsInt = [&](const Expr *arg) {
1447 Expr::EvalResult res;
1448 [[maybe_unused]] bool evalSucceed =
1449 arg->EvaluateAsInt(res, cgm.getASTContext());
1450 assert(evalSucceed && "expression should be able to evaluate as int");
1451 return res.Val.getInt().getZExtValue();
1452 };
1453
1454 bool isWrite = false;
1455 if (e->getNumArgs() > 1)
1456 isWrite = evaluateOperandAsInt(e->getArg(1));
1457
1458 int locality = 3;
1459 if (e->getNumArgs() > 2)
1460 locality = evaluateOperandAsInt(e->getArg(2));
1461
1462 mlir::Value address = emitScalarExpr(e->getArg(0));
1463 cir::PrefetchOp::create(builder, loc, address, locality, isWrite);
1464 return RValue::get(nullptr);
1465 }
1466 case Builtin::BI__builtin_readcyclecounter:
1467 case Builtin::BI__builtin_readsteadycounter:
1468 return errorBuiltinNYI(*this, e, builtinID);
1469 case Builtin::BI__builtin___clear_cache: {
1470 mlir::Value begin =
1471 builder.createPtrBitcast(emitScalarExpr(e->getArg(0)), cgm.voidTy);
1472 mlir::Value end =
1473 builder.createPtrBitcast(emitScalarExpr(e->getArg(1)), cgm.voidTy);
1474 cir::ClearCacheOp::create(builder, getLoc(e->getSourceRange()), begin, end);
1475 return RValue::get(nullptr);
1476 }
1477 case Builtin::BI__builtin_trap:
1478 emitTrap(loc, /*createNewBlock=*/true);
1479 return RValue::getIgnored();
1480 case Builtin::BI__builtin_verbose_trap:
1482 emitTrap(loc, /*createNewBlock=*/true);
1483 return RValue::getIgnored();
1484 case Builtin::BI__debugbreak:
1485 return errorBuiltinNYI(*this, e, builtinID);
1486 case Builtin::BI__builtin_unreachable:
1487 emitUnreachable(e->getExprLoc(), /*createNewBlock=*/true);
1488 return RValue::getIgnored();
1489 case Builtin::BI__builtin_powi:
1490 case Builtin::BI__builtin_powif:
1491 case Builtin::BI__builtin_powil: {
1492 mlir::Value src0 = emitScalarExpr(e->getArg(0));
1493 mlir::Value src1 = emitScalarExpr(e->getArg(1));
1494 return RValue::get(builder.emitIntrinsicCallOp(
1495 getLoc(e->getExprLoc()), "powi", src0.getType(),
1496 mlir::ValueRange{src0, src1}));
1497 }
1498 case Builtin::BI__builtin_frexpl:
1499 case Builtin::BI__builtin_frexp:
1500 case Builtin::BI__builtin_frexpf:
1501 case Builtin::BI__builtin_frexpf128:
1502 case Builtin::BI__builtin_frexpf16: {
1503 mlir::Value val = emitScalarExpr(e->getArg(0));
1504 mlir::Value ptr = emitScalarExpr(e->getArg(1));
1505 mlir::Type fpTy = val.getType();
1506 QualType intQualTy = e->getArg(1)->getType()->getPointeeType();
1507 mlir::Type intTy = convertType(intQualTy);
1508 mlir::Location callLoc = getLoc(e->getExprLoc());
1509 auto frexpOp = cir::FrexpOp::create(builder, callLoc, fpTy, intTy, val);
1510 LValue lv = makeNaturalAlignAddrLValue(ptr, intQualTy);
1511 emitStoreOfScalar(frexpOp.getExp(), lv, /*isInit=*/false);
1512 return RValue::get(frexpOp.getResult());
1513 }
1514 case Builtin::BImodf:
1515 case Builtin::BImodff:
1516 case Builtin::BImodfl:
1517 case Builtin::BI__builtin_modf:
1518 case Builtin::BI__builtin_modff:
1519 case Builtin::BI__builtin_modfl: {
1520 mlir::Value val = emitScalarExpr(e->getArg(0));
1521 mlir::Value ptr = emitScalarExpr(e->getArg(1));
1522 mlir::Type fpTy = val.getType();
1523 mlir::Location callLoc = getLoc(e->getExprLoc());
1524 auto modfOp = cir::ModfOp::create(builder, callLoc, fpTy, fpTy, val);
1525 QualType destPtrTy = e->getArg(1)->getType()->getPointeeType();
1526 LValue lv = makeNaturalAlignAddrLValue(ptr, destPtrTy);
1527 emitStoreOfScalar(modfOp.getIntegral(), lv, /*isInit=*/false);
1528 return RValue::get(modfOp.getFractional());
1529 }
1530 case Builtin::BI__builtin_isgreater:
1531 case Builtin::BI__builtin_isgreaterequal:
1532 case Builtin::BI__builtin_isless:
1533 case Builtin::BI__builtin_islessequal:
1534 case Builtin::BI__builtin_islessgreater:
1535 case Builtin::BI__builtin_isunordered: {
1536 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
1537 mlir::Value lhs = emitScalarExpr(e->getArg(0));
1538 mlir::Value rhs = emitScalarExpr(e->getArg(1));
1539 mlir::Location loc = getLoc(e->getBeginLoc());
1540 mlir::Type intTy = convertType(e->getType());
1541
1542 mlir::Value cmpResult;
1543 switch (builtinID) {
1544 case Builtin::BI__builtin_isgreater:
1545 cmpResult = builder.createCompare(loc, cir::CmpOpKind::gt, lhs, rhs);
1546 break;
1547 case Builtin::BI__builtin_isgreaterequal:
1548 cmpResult = builder.createCompare(loc, cir::CmpOpKind::ge, lhs, rhs);
1549 break;
1550 case Builtin::BI__builtin_isless:
1551 cmpResult = builder.createCompare(loc, cir::CmpOpKind::lt, lhs, rhs);
1552 break;
1553 case Builtin::BI__builtin_islessequal:
1554 cmpResult = builder.createCompare(loc, cir::CmpOpKind::le, lhs, rhs);
1555 break;
1556 case Builtin::BI__builtin_islessgreater:
1557 cmpResult = builder.createCompare(loc, cir::CmpOpKind::one, lhs, rhs);
1558 break;
1559 case Builtin::BI__builtin_isunordered:
1560 cmpResult = builder.createCompare(loc, cir::CmpOpKind::uno, lhs, rhs);
1561 break;
1562 default:
1563 llvm_unreachable("Unknown ordered comparison");
1564 }
1565 return RValue::get(builder.createBoolToInt(cmpResult, intTy));
1566 }
1567 // From https://clang.llvm.org/docs/LanguageExtensions.html#builtin-isfpclass
1568 //
1569 // The `__builtin_isfpclass()` builtin is a generalization of functions
1570 // isnan, isinf, isfinite and some others defined by the C standard. It tests
1571 // if the floating-point value, specified by the first argument, falls into
1572 // any of data classes, specified by the second argument.
1573 case Builtin::BI__builtin_isnan: {
1574 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
1575 mlir::Value v = emitScalarExpr(e->getArg(0));
1577 mlir::Location loc = getLoc(e->getBeginLoc());
1578 return RValue::get(builder.createBoolToInt(
1579 builder.createIsFPClass(loc, v, cir::FPClassTest::Nan),
1580 convertType(e->getType())));
1581 }
1582
1583 case Builtin::BI__builtin_issignaling: {
1584 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
1585 mlir::Value v = emitScalarExpr(e->getArg(0));
1586 mlir::Location loc = getLoc(e->getBeginLoc());
1587 return RValue::get(builder.createBoolToInt(
1588 builder.createIsFPClass(loc, v, cir::FPClassTest::SignalingNaN),
1589 convertType(e->getType())));
1590 }
1591
1592 case Builtin::BI__builtin_isinf: {
1593 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
1594 mlir::Value v = emitScalarExpr(e->getArg(0));
1596 mlir::Location loc = getLoc(e->getBeginLoc());
1597 return RValue::get(builder.createBoolToInt(
1598 builder.createIsFPClass(loc, v, cir::FPClassTest::Infinity),
1599 convertType(e->getType())));
1600 }
1601 case Builtin::BIfinite:
1602 case Builtin::BI__finite:
1603 case Builtin::BIfinitef:
1604 case Builtin::BI__finitef:
1605 case Builtin::BIfinitel:
1606 case Builtin::BI__finitel:
1607 case Builtin::BI__builtin_isfinite: {
1608 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
1609 mlir::Value v = emitScalarExpr(e->getArg(0));
1611 mlir::Location loc = getLoc(e->getBeginLoc());
1612 return RValue::get(builder.createBoolToInt(
1613 builder.createIsFPClass(loc, v, cir::FPClassTest::Finite),
1614 convertType(e->getType())));
1615 }
1616
1617 case Builtin::BI__builtin_isnormal: {
1618 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
1619 mlir::Value v = emitScalarExpr(e->getArg(0));
1620 mlir::Location loc = getLoc(e->getBeginLoc());
1621 return RValue::get(builder.createBoolToInt(
1622 builder.createIsFPClass(loc, v, cir::FPClassTest::Normal),
1623 convertType(e->getType())));
1624 }
1625
1626 case Builtin::BI__builtin_issubnormal: {
1627 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
1628 mlir::Value v = emitScalarExpr(e->getArg(0));
1629 mlir::Location loc = getLoc(e->getBeginLoc());
1630 return RValue::get(builder.createBoolToInt(
1631 builder.createIsFPClass(loc, v, cir::FPClassTest::Subnormal),
1632 convertType(e->getType())));
1633 }
1634
1635 case Builtin::BI__builtin_iszero: {
1636 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
1637 mlir::Value v = emitScalarExpr(e->getArg(0));
1638 mlir::Location loc = getLoc(e->getBeginLoc());
1639 return RValue::get(builder.createBoolToInt(
1640 builder.createIsFPClass(loc, v, cir::FPClassTest::Zero),
1641 convertType(e->getType())));
1642 }
1643 case Builtin::BI__builtin_isfpclass: {
1644 Expr::EvalResult result;
1645 if (!e->getArg(1)->EvaluateAsInt(result, cgm.getASTContext()))
1646 break;
1647
1648 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
1649 mlir::Value v = emitScalarExpr(e->getArg(0));
1650 uint64_t test = result.Val.getInt().getLimitedValue();
1651 mlir::Location loc = getLoc(e->getBeginLoc());
1652 //
1653 return RValue::get(builder.createBoolToInt(
1654 builder.createIsFPClass(loc, v, cir::FPClassTest(test)),
1655 convertType(e->getType())));
1656 }
1657 case Builtin::BI__builtin_nondeterministic_value: {
1658 mlir::Type ty = convertType(e->getArg(0)->getType());
1659 mlir::Value result =
1660 cir::ConstantOp::create(builder, loc, ty, cir::PoisonAttr::get(ty));
1661 result = cir::FreezeOp::create(builder, loc, result);
1662 return RValue::get(result);
1663 }
1664 case Builtin::BI__builtin_elementwise_abs: {
1665 mlir::Type cirTy = convertType(e->getArg(0)->getType());
1666 bool isIntTy = cir::isIntOrVectorOfIntType(cirTy);
1667 if (!isIntTy)
1668 return emitUnaryFPBuiltin<cir::FAbsOp>(*this, *e);
1669 mlir::Value arg = emitScalarExpr(e->getArg(0));
1670 mlir::Value result = cir::AbsOp::create(builder, getLoc(e->getExprLoc()),
1671 arg.getType(), arg, false);
1672 return RValue::get(result);
1673 }
1674 case Builtin::BI__builtin_elementwise_bitreverse:
1675 case Builtin::BI__builtin_elementwise_popcount:
1676 case Builtin::BI__builtin_elementwise_canonicalize:
1677 case Builtin::BI__builtin_elementwise_copysign:
1678 return errorBuiltinNYI(*this, e, builtinID);
1679 case Builtin::BI__builtin_elementwise_fshl: {
1680 mlir::Location loc = getLoc(e->getExprLoc());
1681 mlir::Value a = emitScalarExpr(e->getArg(0));
1682 mlir::Value b = emitScalarExpr(e->getArg(1));
1683 mlir::Value c = emitScalarExpr(e->getArg(2));
1684 return RValue::get(builder.emitIntrinsicCallOp(loc, "fshl", a.getType(),
1685 mlir::ValueRange{a, b, c}));
1686 }
1687 case Builtin::BI__builtin_elementwise_fshr: {
1688 mlir::Location loc = getLoc(e->getExprLoc());
1689 mlir::Value a = emitScalarExpr(e->getArg(0));
1690 mlir::Value b = emitScalarExpr(e->getArg(1));
1691 mlir::Value c = emitScalarExpr(e->getArg(2));
1692 return RValue::get(builder.emitIntrinsicCallOp(loc, "fshr", a.getType(),
1693 mlir::ValueRange{a, b, c}));
1694 }
1695 case Builtin::BI__builtin_elementwise_clmul:
1696 case Builtin::BI__builtin_elementwise_pext:
1697 case Builtin::BI__builtin_elementwise_pdep:
1698 return errorBuiltinNYI(*this, e, builtinID);
1699 case Builtin::BI__builtin_elementwise_add_sat:
1700 case Builtin::BI__builtin_elementwise_sub_sat: {
1701 // cir.add/cir.sub do not model i1 arithmetic, so a bool-element
1702 // saturating add/sub is not representable through the saturated op.
1703 // Bail before emitScalarExpr: an ext-vector-of-bool operand would
1704 // otherwise hit the NYI bool-vector load, which returns a null value
1705 // and would crash op0.getType().
1706 QualType argTy = e->getArg(0)->getType();
1707 if (argTy->isBooleanType() || argTy->isExtVectorBoolType()) {
1708 cgm.errorNYI(e->getSourceRange(),
1709 "saturating add/sub on a boolean operand");
1710 return RValue::get(nullptr);
1711 }
1712 mlir::Location loc = getLoc(e->getExprLoc());
1713 mlir::Value op0 = emitScalarExpr(e->getArg(0));
1714 mlir::Value op1 = emitScalarExpr(e->getArg(1));
1715 assert(cir::isIntOrVectorOfIntType(op0.getType()) &&
1716 "elementwise saturating add/sub requires integer operands");
1717 mlir::Value val =
1718 builtinIDIfNoAsmLabel == Builtin::BI__builtin_elementwise_add_sat
1719 ? builder.createAdd(loc, op0, op1, cir::OverflowBehavior::Saturated)
1720 : builder.createSub(loc, op0, op1,
1722 return RValue::get(val);
1723 }
1724 case Builtin::BI__builtin_elementwise_max:
1725 case Builtin::BI__builtin_elementwise_min:
1726 case Builtin::BI__builtin_elementwise_maxnum:
1727 case Builtin::BI__builtin_elementwise_minnum:
1728 case Builtin::BI__builtin_elementwise_maximum:
1729 case Builtin::BI__builtin_elementwise_minimum:
1730 case Builtin::BI__builtin_elementwise_maximumnum:
1731 case Builtin::BI__builtin_elementwise_minimumnum:
1732 case Builtin::BI__builtin_reduce_max:
1733 case Builtin::BI__builtin_reduce_min:
1734 case Builtin::BI__builtin_reduce_add:
1735 case Builtin::BI__builtin_reduce_mul:
1736 return errorBuiltinNYI(*this, e, builtinID);
1737 case Builtin::BI__builtin_reduce_xor:
1739 e, "vector.reduce.xor",
1741 .getElementType());
1742 case Builtin::BI__builtin_reduce_or:
1744 e, "vector.reduce.or",
1746 .getElementType());
1747 case Builtin::BI__builtin_reduce_and:
1749 e, "vector.reduce.and",
1751 .getElementType());
1752 case Builtin::BI__builtin_reduce_assoc_fadd:
1753 case Builtin::BI__builtin_reduce_in_order_fadd:
1754 case Builtin::BI__builtin_reduce_maximum:
1755 case Builtin::BI__builtin_reduce_minimum:
1756 case Builtin::BI__builtin_matrix_transpose:
1757 case Builtin::BI__builtin_matrix_column_major_load:
1758 case Builtin::BI__builtin_matrix_column_major_store:
1759 case Builtin::BI__builtin_masked_load:
1760 case Builtin::BI__builtin_masked_expand_load:
1761 case Builtin::BI__builtin_masked_gather:
1762 case Builtin::BI__builtin_masked_store:
1763 case Builtin::BI__builtin_masked_compress_store:
1764 case Builtin::BI__builtin_masked_scatter:
1765 return errorBuiltinNYI(*this, e, builtinID);
1766 case Builtin::BI__builtin_isinf_sign: {
1767 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
1768 mlir::Location loc = getLoc(e->getBeginLoc());
1769 mlir::Value arg = emitScalarExpr(e->getArg(0));
1770 mlir::Value isInf =
1771 builder.createIsFPClass(loc, arg, cir::FPClassTest::Infinity);
1772 mlir::Value isNeg = emitSignBit(loc, *this, arg);
1773 mlir::Type intTy = convertType(e->getType());
1774 cir::ConstantOp zero = builder.getNullValue(intTy, loc);
1775 cir::ConstantOp one = builder.getConstant(loc, cir::IntAttr::get(intTy, 1));
1776 cir::ConstantOp negativeOne =
1777 builder.getConstant(loc, cir::IntAttr::get(intTy, -1));
1778 mlir::Value signResult = builder.createSelect(loc, isNeg, negativeOne, one);
1779 mlir::Value result = builder.createSelect(loc, isInf, signResult, zero);
1780 return RValue::get(result);
1781 }
1782 case Builtin::BI__builtin_flt_rounds: {
1783 mlir::Location loc = getLoc(e->getExprLoc());
1784 mlir::Type resultType = convertType(e->getType());
1785 mlir::Value result =
1786 builder.emitIntrinsicCallOp(loc, "get.rounding", resultType);
1787 if (result.getType() != resultType)
1788 result =
1789 builder.createCast(loc, cir::CastKind::integral, result, resultType);
1790 return RValue::get(result);
1791 }
1792 case Builtin::BI__builtin_set_flt_rounds: {
1793 mlir::Location loc = getLoc(e->getExprLoc());
1794 mlir::Value v = emitScalarExpr(e->getArg(0));
1795 builder.emitIntrinsicCallOp(loc, "set.rounding", builder.getVoidTy(),
1796 mlir::ValueRange{v});
1797 return RValue::get(nullptr);
1798 }
1799 case Builtin::BI__builtin_fpclassify: {
1800 CIRGenFunction::CIRGenFPOptionsRAII fPOptsRAII(*this, e);
1801 mlir::Location loc = getLoc(e->getBeginLoc());
1802 mlir::Value value = emitScalarExpr(e->getArg(5));
1803 mlir::Type resultTy = convertType(e->getType());
1804 // if isZero then
1805 // result = FP_ZERO
1806 // elseif isNan then
1807 // result = FP_NAN
1808 // elseif isInfinity then
1809 // result = FP_INFINITE
1810 // elseif isNormal then
1811 // result = FP_NORMAL
1812 // else
1813 // result = FP_SUBNORMAL
1814 auto isZero =
1815 cir::IsFPClassOp::create(builder, loc, value, cir::FPClassTest::Zero);
1816 mlir::Value result =
1817 cir::TernaryOp::create(
1818 builder, loc, isZero,
1819 /*thenBuilder=*/
1820 [&](mlir::OpBuilder &opBuilder, mlir::Location location) {
1821 mlir::Value zeroLiteral = emitScalarExpr(e->getArg(4));
1822 cir::YieldOp::create(opBuilder, location, zeroLiteral);
1823 },
1824 /*elseBuilder=*/
1825 [&](mlir::OpBuilder &opBuilder, mlir::Location location) {
1826 auto isNan = cir::IsFPClassOp::create(opBuilder, location, value,
1827 cir::FPClassTest::Nan);
1828 mlir::Value nanResult =
1829 cir::TernaryOp::create(
1830 opBuilder, location, isNan,
1831 /*thenBuilder=*/
1832 [&](mlir::OpBuilder &opBuilder, mlir::Location location) {
1833 mlir::Value nanLiteral = emitScalarExpr(e->getArg(0));
1834 cir::YieldOp::create(opBuilder, location, nanLiteral);
1835 },
1836 /*elseBuilder=*/
1837 [&](mlir::OpBuilder &opBuilder, mlir::Location location) {
1838 auto isInfinity = cir::IsFPClassOp::create(
1839 opBuilder, location, value,
1840 cir::FPClassTest::Infinity);
1841 mlir::Value infResult =
1842 cir::TernaryOp::create(
1843 opBuilder, location, isInfinity,
1844 /*thenBuilder=*/
1845 [&](mlir::OpBuilder &opBuilder,
1846 mlir::Location location) {
1847 mlir::Value infinityLiteral =
1848 emitScalarExpr(e->getArg(1));
1849 cir::YieldOp::create(opBuilder, location,
1850 infinityLiteral);
1851 },
1852 /*elseBuilder=*/
1853 [&](mlir::OpBuilder &opBuilder,
1854 mlir::Location location) {
1855 auto isNormal = cir::IsFPClassOp::create(
1856 opBuilder, location, value,
1857 cir::FPClassTest::Normal);
1858 mlir::Value fpNormal =
1859 emitScalarExpr(e->getArg(2));
1860 mlir::Value fpSubnormal =
1861 emitScalarExpr(e->getArg(3));
1862 mlir::Value returnValue =
1863 cir::SelectOp::create(
1864 opBuilder, location, resultTy,
1865 isNormal, fpNormal, fpSubnormal);
1866 cir::YieldOp::create(opBuilder, location,
1867 returnValue);
1868 })
1869 .getResult();
1870 cir::YieldOp::create(opBuilder, location, infResult);
1871 })
1872 .getResult();
1873 cir::YieldOp::create(opBuilder, location, nanResult);
1874 })
1875 .getResult();
1876 return RValue::get(result);
1877 }
1878 case Builtin::BIalloca:
1879 case Builtin::BI_alloca:
1880 case Builtin::BI__builtin_alloca_uninitialized:
1881 case Builtin::BI__builtin_alloca:
1882 return emitBuiltinAlloca(*this, e, builtinID);
1883 case Builtin::BI__builtin_alloca_with_align_uninitialized:
1884 case Builtin::BI__builtin_alloca_with_align:
1885 case Builtin::BI__builtin_infer_alloc_token:
1886 return errorBuiltinNYI(*this, e, builtinID);
1887 case Builtin::BIbzero:
1888 case Builtin::BI__builtin_bzero: {
1889 mlir::Location loc = getLoc(e->getSourceRange());
1890 Address destPtr = emitPointerWithAlignment(e->getArg(0));
1891 Address destPtrCast = destPtr.withElementType(builder, cgm.voidTy);
1892 mlir::Value size = emitScalarExpr(e->getArg(1));
1893 mlir::Value zero = builder.getNullValue(builder.getUInt8Ty(), loc);
1895 builder.createMemSet(loc, destPtrCast, zero, size);
1897 return RValue::getIgnored();
1898 }
1899 case Builtin::BIbcopy:
1900 case Builtin::BI__builtin_bcopy: {
1903 mlir::Value sizeVal = emitScalarExpr(e->getArg(2));
1905 e->getArg(0)->getExprLoc(), fd, 0);
1907 e->getArg(1)->getExprLoc(), fd, 0);
1908 builder.createMemMove(getLoc(e->getSourceRange()), dest.getPointer(),
1909 src.getPointer(), sizeVal);
1910 return RValue::get(nullptr);
1911 }
1912 case Builtin::BI__builtin_char_memchr:
1913 case Builtin::BI__builtin_memchr: {
1914 Address srcPtr = emitPointerWithAlignment(e->getArg(0));
1915 mlir::Value src =
1916 builder.createBitcast(srcPtr.getPointer(), builder.getVoidPtrTy());
1917 mlir::Value pattern = emitScalarExpr(e->getArg(1));
1918 mlir::Value len = emitScalarExpr(e->getArg(2));
1919 mlir::Value res = cir::MemChrOp::create(builder, getLoc(e->getExprLoc()),
1920 src, pattern, len);
1921 return RValue::get(res);
1922 }
1923 case Builtin::BImemcpy:
1924 case Builtin::BI__builtin_memcpy:
1925 case Builtin::BImempcpy:
1926 case Builtin::BI__builtin_mempcpy:
1927 case Builtin::BI__builtin_memcpy_inline:
1928 case Builtin::BI__builtin___memcpy_chk:
1929 case Builtin::BI__builtin_objc_memmove_collectable:
1930 case Builtin::BI__builtin___memmove_chk:
1931 case Builtin::BI__builtin_trivially_relocate:
1932 case Builtin::BImemmove:
1933 case Builtin::BI__builtin_memmove:
1934 case Builtin::BImemset:
1935 case Builtin::BI__builtin_memset:
1936 case Builtin::BI__builtin_memset_inline:
1937 case Builtin::BI__builtin___memset_chk:
1938 case Builtin::BI__builtin_wmemchr:
1939 case Builtin::BI__builtin_wmemcmp:
1940 break; // Handled as library calls below.
1941 case Builtin::BI__builtin_dwarf_cfa:
1942 return errorBuiltinNYI(*this, e, builtinID);
1943 case Builtin::BI__builtin_return_address: {
1944 llvm::APSInt level = e->getArg(0)->EvaluateKnownConstInt(getContext());
1945 return RValue::get(cir::ReturnAddrOp::create(
1946 builder, getLoc(e->getExprLoc()),
1947 builder.getConstAPInt(loc, builder.getUInt32Ty(), level)));
1948 }
1949 case Builtin::BI_ReturnAddress: {
1950 return RValue::get(cir::ReturnAddrOp::create(
1951 builder, getLoc(e->getExprLoc()),
1952 builder.getConstInt(loc, builder.getUInt32Ty(), 0)));
1953 }
1954 case Builtin::BI__builtin_frame_address: {
1955 llvm::APSInt level = e->getArg(0)->EvaluateKnownConstInt(getContext());
1956 mlir::Location loc = getLoc(e->getExprLoc());
1957 mlir::Value addr = cir::FrameAddrOp::create(
1958 builder, loc, allocaInt8PtrTy,
1959 builder.getConstAPInt(loc, builder.getUInt32Ty(), level));
1960 return RValue::get(
1961 builder.createCast(loc, cir::CastKind::bitcast, addr, voidPtrTy));
1962 }
1963 case Builtin::BI__builtin_extract_return_addr:
1964 case Builtin::BI__builtin_frob_return_addr:
1965 case Builtin::BI__builtin_dwarf_sp_column:
1966 case Builtin::BI__builtin_init_dwarf_reg_size_table:
1967 case Builtin::BI__builtin_eh_return:
1968 case Builtin::BI__builtin_unwind_init:
1969 case Builtin::BI__builtin_extend_pointer:
1970 return errorBuiltinNYI(*this, e, builtinID);
1971 case Builtin::BI__builtin_setjmp: {
1973 mlir::Location loc = getLoc(e->getExprLoc());
1974
1975 cir::PointerType voidPtrTy = builder.getVoidPtrTy();
1976 cir::PointerType ppTy = builder.getPointerTo(voidPtrTy);
1977 Address castBuf = buf.withElementType(builder, voidPtrTy);
1978
1980 if (getTarget().getTriple().isSystemZ()) {
1981 cgm.errorNYI(e->getExprLoc(), "setjmp on SystemZ");
1982 return {};
1983 }
1984
1985 mlir::Value frameAddress =
1986 cir::FrameAddrOp::create(builder, loc, voidPtrTy,
1987 mlir::ValueRange{builder.getUInt32(0, loc)})
1988 .getResult();
1989
1990 builder.createStore(loc, frameAddress, castBuf);
1991
1992 mlir::Value stacksave =
1993 cir::StackSaveOp::create(builder, loc, voidPtrTy).getResult();
1994 cir::PtrStrideOp stackSaveSlot = cir::PtrStrideOp::create(
1995 builder, loc, ppTy, castBuf.getPointer(), builder.getSInt32(2, loc));
1996 llvm::TypeSize voidPtrTySize =
1997 cgm.getDataLayout().getTypeAllocSize(voidPtrTy);
1998 CharUnits slotAlign = castBuf.getAlignment().alignmentAtOffset(
1999 CharUnits().fromQuantity(2 * voidPtrTySize));
2000 Address slotAddr = Address(stackSaveSlot, voidPtrTy, slotAlign);
2001 builder.createStore(loc, stacksave, slotAddr);
2002 auto op = cir::EhSetjmpOp::create(builder, loc, castBuf.getPointer());
2003 return RValue::get(op);
2004 }
2005 case Builtin::BI__builtin_longjmp: {
2006 mlir::Value buf = emitScalarExpr(e->getArg(0));
2007 mlir::Location loc = getLoc(e->getExprLoc());
2008
2009 cir::EhLongjmpOp::create(builder, loc, buf);
2010 cir::UnreachableOp::create(builder, loc);
2011 return RValue::get(nullptr);
2012 }
2013 case Builtin::BI__builtin_launder: {
2014 const Expr *arg = e->getArg(0);
2015 QualType argTy = arg->getType()->getPointeeType();
2016 mlir::Value ptr = emitScalarExpr(arg);
2017
2018 if (cgm.getCodeGenOpts().StrictVTablePointers &&
2019 argTy.requiresBuiltinLaunder(cgm.getASTContext())) {
2020 mlir::Location loc = getLoc(e->getExprLoc());
2021 ptr = cir::LaunderOp::create(builder, loc, ptr).getResult();
2022 }
2023 return RValue::get(ptr);
2024 }
2025 case Builtin::BI__sync_fetch_and_add:
2026 case Builtin::BI__sync_fetch_and_sub:
2027 case Builtin::BI__sync_fetch_and_or:
2028 case Builtin::BI__sync_fetch_and_and:
2029 case Builtin::BI__sync_fetch_and_xor:
2030 case Builtin::BI__sync_fetch_and_nand:
2031 case Builtin::BI__sync_add_and_fetch:
2032 case Builtin::BI__sync_sub_and_fetch:
2033 case Builtin::BI__sync_and_and_fetch:
2034 case Builtin::BI__sync_or_and_fetch:
2035 case Builtin::BI__sync_xor_and_fetch:
2036 case Builtin::BI__sync_nand_and_fetch:
2037 case Builtin::BI__sync_val_compare_and_swap:
2038 case Builtin::BI__sync_bool_compare_and_swap:
2039 case Builtin::BI__sync_lock_test_and_set:
2040 case Builtin::BI__sync_lock_release:
2041 case Builtin::BI__sync_swap:
2042 return errorBuiltinNYI(*this, e, builtinID);
2043 case Builtin::BI__sync_fetch_and_add_1:
2044 case Builtin::BI__sync_fetch_and_add_2:
2045 case Builtin::BI__sync_fetch_and_add_4:
2046 case Builtin::BI__sync_fetch_and_add_8:
2047 case Builtin::BI__sync_fetch_and_add_16:
2048 return emitBinaryAtomic(*this, cir::AtomicFetchKind::Add, e);
2049 case Builtin::BI__sync_fetch_and_sub_1:
2050 case Builtin::BI__sync_fetch_and_sub_2:
2051 case Builtin::BI__sync_fetch_and_sub_4:
2052 case Builtin::BI__sync_fetch_and_sub_8:
2053 case Builtin::BI__sync_fetch_and_sub_16:
2054 return emitBinaryAtomic(*this, cir::AtomicFetchKind::Sub, e);
2055 case Builtin::BI__sync_fetch_and_or_1:
2056 case Builtin::BI__sync_fetch_and_or_2:
2057 case Builtin::BI__sync_fetch_and_or_4:
2058 case Builtin::BI__sync_fetch_and_or_8:
2059 case Builtin::BI__sync_fetch_and_or_16:
2060 return emitBinaryAtomic(*this, cir::AtomicFetchKind::Or, e);
2061 case Builtin::BI__sync_fetch_and_and_1:
2062 case Builtin::BI__sync_fetch_and_and_2:
2063 case Builtin::BI__sync_fetch_and_and_4:
2064 case Builtin::BI__sync_fetch_and_and_8:
2065 case Builtin::BI__sync_fetch_and_and_16:
2066 return emitBinaryAtomic(*this, cir::AtomicFetchKind::And, e);
2067 case Builtin::BI__sync_fetch_and_xor_1:
2068 case Builtin::BI__sync_fetch_and_xor_2:
2069 case Builtin::BI__sync_fetch_and_xor_4:
2070 case Builtin::BI__sync_fetch_and_xor_8:
2071 case Builtin::BI__sync_fetch_and_xor_16:
2072 return emitBinaryAtomic(*this, cir::AtomicFetchKind::Xor, e);
2073 case Builtin::BI__sync_fetch_and_nand_1:
2074 case Builtin::BI__sync_fetch_and_nand_2:
2075 case Builtin::BI__sync_fetch_and_nand_4:
2076 case Builtin::BI__sync_fetch_and_nand_8:
2077 case Builtin::BI__sync_fetch_and_nand_16:
2078 return emitBinaryAtomic(*this, cir::AtomicFetchKind::Nand, e);
2079 case Builtin::BI__sync_fetch_and_min:
2080 case Builtin::BI__sync_fetch_and_max:
2081 case Builtin::BI__sync_fetch_and_umin:
2082 case Builtin::BI__sync_fetch_and_umax:
2083 return errorBuiltinNYI(*this, e, builtinID);
2084 return getUndefRValue(e->getType());
2085 case Builtin::BI__sync_add_and_fetch_1:
2086 case Builtin::BI__sync_add_and_fetch_2:
2087 case Builtin::BI__sync_add_and_fetch_4:
2088 case Builtin::BI__sync_add_and_fetch_8:
2089 case Builtin::BI__sync_add_and_fetch_16:
2090 return emitBinaryAtomicPost<cir::AddOp>(*this, cir::AtomicFetchKind::Add,
2091 e);
2092 case Builtin::BI__sync_sub_and_fetch_1:
2093 case Builtin::BI__sync_sub_and_fetch_2:
2094 case Builtin::BI__sync_sub_and_fetch_4:
2095 case Builtin::BI__sync_sub_and_fetch_8:
2096 case Builtin::BI__sync_sub_and_fetch_16:
2097 return emitBinaryAtomicPost<cir::SubOp>(*this, cir::AtomicFetchKind::Sub,
2098 e);
2099 case Builtin::BI__sync_and_and_fetch_1:
2100 case Builtin::BI__sync_and_and_fetch_2:
2101 case Builtin::BI__sync_and_and_fetch_4:
2102 case Builtin::BI__sync_and_and_fetch_8:
2103 case Builtin::BI__sync_and_and_fetch_16:
2104 return emitBinaryAtomicPost<cir::AndOp>(*this, cir::AtomicFetchKind::And,
2105 e);
2106 case Builtin::BI__sync_or_and_fetch_1:
2107 case Builtin::BI__sync_or_and_fetch_2:
2108 case Builtin::BI__sync_or_and_fetch_4:
2109 case Builtin::BI__sync_or_and_fetch_8:
2110 case Builtin::BI__sync_or_and_fetch_16:
2111 return emitBinaryAtomicPost<cir::OrOp>(*this, cir::AtomicFetchKind::Or, e);
2112 case Builtin::BI__sync_xor_and_fetch_1:
2113 case Builtin::BI__sync_xor_and_fetch_2:
2114 case Builtin::BI__sync_xor_and_fetch_4:
2115 case Builtin::BI__sync_xor_and_fetch_8:
2116 case Builtin::BI__sync_xor_and_fetch_16:
2117 return emitBinaryAtomicPost<cir::XorOp>(*this, cir::AtomicFetchKind::Xor,
2118 e);
2119 case Builtin::BI__sync_nand_and_fetch_1:
2120 case Builtin::BI__sync_nand_and_fetch_2:
2121 case Builtin::BI__sync_nand_and_fetch_4:
2122 case Builtin::BI__sync_nand_and_fetch_8:
2123 case Builtin::BI__sync_nand_and_fetch_16:
2124 return emitBinaryAtomicPost<cir::AndOp>(*this, cir::AtomicFetchKind::Nand,
2125 e, /*invert=*/true);
2126 case Builtin::BI__sync_val_compare_and_swap_1:
2127 case Builtin::BI__sync_val_compare_and_swap_2:
2128 case Builtin::BI__sync_val_compare_and_swap_4:
2129 case Builtin::BI__sync_val_compare_and_swap_8:
2130 case Builtin::BI__sync_val_compare_and_swap_16:
2131 case Builtin::BI__sync_bool_compare_and_swap_1:
2132 case Builtin::BI__sync_bool_compare_and_swap_2:
2133 case Builtin::BI__sync_bool_compare_and_swap_4:
2134 case Builtin::BI__sync_bool_compare_and_swap_8:
2135 case Builtin::BI__sync_bool_compare_and_swap_16:
2136 case Builtin::BI__sync_swap_1:
2137 case Builtin::BI__sync_swap_2:
2138 case Builtin::BI__sync_swap_4:
2139 case Builtin::BI__sync_swap_8:
2140 case Builtin::BI__sync_swap_16:
2141 case Builtin::BI__sync_lock_test_and_set_1:
2142 case Builtin::BI__sync_lock_test_and_set_2:
2143 case Builtin::BI__sync_lock_test_and_set_4:
2144 case Builtin::BI__sync_lock_test_and_set_8:
2145 case Builtin::BI__sync_lock_test_and_set_16:
2146 case Builtin::BI__sync_lock_release_1:
2147 case Builtin::BI__sync_lock_release_2:
2148 case Builtin::BI__sync_lock_release_4:
2149 case Builtin::BI__sync_lock_release_8:
2150 case Builtin::BI__sync_lock_release_16:
2151 return errorBuiltinNYI(*this, e, builtinID);
2152 case Builtin::BI__sync_synchronize: {
2153 // We assume this is supposed to correspond to a C++0x-style
2154 // sequentially-consistent fence (i.e. this is only usable for
2155 // synchronization, not device I/O or anything like that). This intrinsic
2156 // is really badly designed in the sense that in theory, there isn't
2157 // any way to safely use it... but in practice, it mostly works
2158 // to use it with non-atomic loads and stores to get acquire/release
2159 // semantics.
2160 cir::AtomicFenceOp::create(
2161 builder, getLoc(e->getSourceRange()),
2162 cir::MemOrder::SequentiallyConsistent,
2163 cir::SyncScopeKindAttr::get(&getMLIRContext(),
2164 cir::SyncScopeKind::System));
2165 return RValue::get(nullptr);
2166 }
2167 case Builtin::BI__builtin_nontemporal_load: {
2169 LValue lv = makeAddrLValue(addr, e->getType(),
2171 lv.setNontemporal(true);
2172 mlir::Value val = emitLoadOfScalar(lv, e->getExprLoc());
2173 return RValue::get(val);
2174 }
2175 case Builtin::BI__builtin_nontemporal_store: {
2176 mlir::Value val = emitScalarExpr(e->getArg(0));
2178 val = emitToMemory(val, e->getArg(0)->getType());
2179 LValue lv = makeAddrLValue(addr, e->getArg(0)->getType(),
2181 lv.setNontemporal(true);
2182 emitStoreOfScalar(val, lv, /*isInit=*/false);
2183 return RValue::get(nullptr);
2184 }
2185 case Builtin::BI__c11_atomic_is_lock_free:
2186 case Builtin::BI__atomic_is_lock_free:
2187 return emitAtomicIsLockFree(*this, e, builtinID);
2188 case Builtin::BI__atomic_test_and_set:
2189 case Builtin::BI__atomic_clear:
2190 return errorBuiltinNYI(*this, e, builtinID);
2191 case Builtin::BI__atomic_thread_fence:
2192 case Builtin::BI__c11_atomic_thread_fence: {
2193 emitAtomicFenceOp(*this, e, cir::SyncScopeKind::System);
2194 return RValue::get(nullptr);
2195 }
2196 case Builtin::BI__atomic_signal_fence:
2197 case Builtin::BI__c11_atomic_signal_fence: {
2198 emitAtomicFenceOp(*this, e, cir::SyncScopeKind::SingleThread);
2199 return RValue::get(nullptr);
2200 }
2201 case Builtin::BI__scoped_atomic_thread_fence:
2202 return errorBuiltinNYI(*this, e, builtinID);
2203 case Builtin::BI__builtin_signbit:
2204 case Builtin::BI__builtin_signbitf:
2205 case Builtin::BI__builtin_signbitl: {
2206 CIRGenFunction::CIRGenFPOptionsRAII fPOptsRAII(*this, e);
2207 mlir::Location loc = getLoc(e->getBeginLoc());
2208 mlir::Value value = emitScalarExpr(e->getArg(0));
2209 mlir::Operation *signBitOp = cir::SignBitOp::create(builder, loc, value);
2210 mlir::Value result = builder.createBoolToInt(signBitOp->getResult(0),
2211 convertType(e->getType()));
2212 return RValue::get(result);
2213 }
2214 case Builtin::BI__warn_memset_zero_len:
2215 case Builtin::BI__annotation:
2216 case Builtin::BI__builtin_annotation:
2217 return errorBuiltinNYI(*this, e, builtinID);
2218
2219 case Builtin::BI__builtin_addcb:
2220 case Builtin::BI__builtin_addcs:
2221 case Builtin::BI__builtin_addc:
2222 case Builtin::BI__builtin_addcl:
2223 case Builtin::BI__builtin_addcll:
2224 case Builtin::BI__builtin_subcb:
2225 case Builtin::BI__builtin_subcs:
2226 case Builtin::BI__builtin_subc:
2227 case Builtin::BI__builtin_subcl:
2228 case Builtin::BI__builtin_subcll: {
2229 // Multiprecision add/sub-with-carry. Lower as two chained checked
2230 // add/sub overflow ops, matching classic CodeGen:
2231 // sum1, carry1 = x +/- y
2232 // result, carry2 = sum1 +/- carryin
2233 // *carryout = carry1 | carry2
2234 // All operands and the result share the builtin's integer type, so no
2235 // encompassing-type widening is needed.
2236 mlir::Value x = emitScalarExpr(e->getArg(0));
2237 mlir::Value y = emitScalarExpr(e->getArg(1));
2238 mlir::Value carryin = emitScalarExpr(e->getArg(2));
2239 Address carryOutPtr = emitPointerWithAlignment(e->getArg(3));
2240
2241 mlir::Location loc = getLoc(e->getSourceRange());
2242 mlir::Type resultTy = convertType(e->getType());
2243
2244 static constexpr unsigned addcBuiltins[] = {
2245 Builtin::BI__builtin_addcb, Builtin::BI__builtin_addcs,
2246 Builtin::BI__builtin_addc, Builtin::BI__builtin_addcl,
2247 Builtin::BI__builtin_addcll};
2248 bool isAdd = llvm::is_contained(addcBuiltins, builtinID);
2249
2250 mlir::Value sum1, carry1, sum2, carry2;
2251 if (isAdd) {
2252 std::tie(sum1, carry1) =
2253 emitOverflowOp<cir::AddOverflowOp>(builder, loc, resultTy, x, y);
2254 std::tie(sum2, carry2) = emitOverflowOp<cir::AddOverflowOp>(
2255 builder, loc, resultTy, sum1, carryin);
2256 } else {
2257 std::tie(sum1, carry1) =
2258 emitOverflowOp<cir::SubOverflowOp>(builder, loc, resultTy, x, y);
2259 std::tie(sum2, carry2) = emitOverflowOp<cir::SubOverflowOp>(
2260 builder, loc, resultTy, sum1, carryin);
2261 }
2262
2263 // Combine the two carry bits, then widen to the result integer type.
2264 mlir::Value carryOut = builder.createBoolToInt(
2265 builder.createOr(loc, carry1, carry2), resultTy);
2266 builder.createStore(loc, carryOut, carryOutPtr);
2267 return RValue::get(sum2);
2268 }
2269
2270 case Builtin::BI__builtin_add_overflow:
2271 case Builtin::BI__builtin_sub_overflow:
2272 case Builtin::BI__builtin_mul_overflow: {
2273 const clang::Expr *leftArg = e->getArg(0);
2274 const clang::Expr *rightArg = e->getArg(1);
2275 const clang::Expr *resultArg = e->getArg(2);
2276
2277 clang::QualType resultQTy =
2278 resultArg->getType()->castAs<clang::PointerType>()->getPointeeType();
2279
2280 WidthAndSignedness leftInfo =
2281 getIntegerWidthAndSignedness(cgm.getASTContext(), leftArg->getType());
2282 WidthAndSignedness rightInfo =
2283 getIntegerWidthAndSignedness(cgm.getASTContext(), rightArg->getType());
2284 WidthAndSignedness resultInfo =
2285 getIntegerWidthAndSignedness(cgm.getASTContext(), resultQTy);
2286
2287 // Note we compute the encompassing type with the consideration to the
2288 // result type, so later in LLVM lowering we don't get redundant integral
2289 // extension casts.
2290 WidthAndSignedness encompassingInfo =
2291 EncompassingIntegerType({leftInfo, rightInfo, resultInfo});
2292
2293 auto encompassingCIRTy = cir::IntType::get(
2294 &getMLIRContext(), encompassingInfo.width, encompassingInfo.isSigned);
2295 mlir::Type resultCIRTy = cgm.convertType(resultQTy);
2296
2297 mlir::Value x = emitScalarExpr(leftArg);
2298 mlir::Value y = emitScalarExpr(rightArg);
2299 Address resultPtr = emitPointerWithAlignment(resultArg);
2300
2301 // Extend each operand to the encompassing type, if necessary.
2302 if (x.getType() != encompassingCIRTy) {
2303 x = builder.createCast(mlir::isa<cir::BoolType>(x.getType())
2304 ? cir::CastKind::bool_to_int
2305 : cir::CastKind::integral,
2306 x, encompassingCIRTy);
2307 }
2308
2309 if (y.getType() != encompassingCIRTy) {
2310 y = builder.createCast(mlir::isa<cir::BoolType>(y.getType())
2311 ? cir::CastKind::bool_to_int
2312 : cir::CastKind::integral,
2313 y, encompassingCIRTy);
2314 }
2315
2316 // Perform the operation on the extended values.
2317 mlir::Location loc = getLoc(e->getSourceRange());
2318 mlir::Value result, overflow;
2319 switch (builtinID) {
2320 default:
2321 llvm_unreachable("Unknown overflow builtin id.");
2322 case Builtin::BI__builtin_add_overflow:
2323 std::tie(result, overflow) =
2324 emitOverflowOp<cir::AddOverflowOp>(builder, loc, resultCIRTy, x, y);
2325 break;
2326 case Builtin::BI__builtin_sub_overflow:
2327 std::tie(result, overflow) =
2328 emitOverflowOp<cir::SubOverflowOp>(builder, loc, resultCIRTy, x, y);
2329 break;
2330 case Builtin::BI__builtin_mul_overflow:
2331 std::tie(result, overflow) =
2332 emitOverflowOp<cir::MulOverflowOp>(builder, loc, resultCIRTy, x, y);
2333 break;
2334 }
2335
2336 // Here is a slight difference from the original clang CodeGen:
2337 // - In the original clang CodeGen, the checked arithmetic result is
2338 // first computed as a value of the encompassing type, and then it is
2339 // truncated to the actual result type with a second overflow checking.
2340 // - In CIRGen, the checked arithmetic operation directly produce the
2341 // checked arithmetic result in its expected type, which may be a
2342 // `cir.bool`.
2343 //
2344 // So we don't need a truncation and a second overflow checking here.
2345
2346 // Finally, store the result using the pointer.
2347 bool isVolatile =
2348 resultArg->getType()->getPointeeType().isVolatileQualified();
2349 builder.createStore(loc, result, resultPtr, isVolatile);
2350
2351 return RValue::get(overflow);
2352 }
2353
2354 case Builtin::BI__builtin_uadd_overflow:
2355 case Builtin::BI__builtin_uaddl_overflow:
2356 case Builtin::BI__builtin_uaddll_overflow:
2357 case Builtin::BI__builtin_usub_overflow:
2358 case Builtin::BI__builtin_usubl_overflow:
2359 case Builtin::BI__builtin_usubll_overflow:
2360 case Builtin::BI__builtin_umul_overflow:
2361 case Builtin::BI__builtin_umull_overflow:
2362 case Builtin::BI__builtin_umulll_overflow:
2363 case Builtin::BI__builtin_sadd_overflow:
2364 case Builtin::BI__builtin_saddl_overflow:
2365 case Builtin::BI__builtin_saddll_overflow:
2366 case Builtin::BI__builtin_ssub_overflow:
2367 case Builtin::BI__builtin_ssubl_overflow:
2368 case Builtin::BI__builtin_ssubll_overflow:
2369 case Builtin::BI__builtin_smul_overflow:
2370 case Builtin::BI__builtin_smull_overflow:
2371 case Builtin::BI__builtin_smulll_overflow: {
2372 // Scalarize our inputs.
2373 mlir::Value x = emitScalarExpr(e->getArg(0));
2374 mlir::Value y = emitScalarExpr(e->getArg(1));
2375
2376 const clang::Expr *resultArg = e->getArg(2);
2377 Address resultPtr = emitPointerWithAlignment(resultArg);
2378
2379 clang::QualType resultQTy =
2380 resultArg->getType()->castAs<clang::PointerType>()->getPointeeType();
2381 auto resultCIRTy = mlir::cast<cir::IntType>(cgm.convertType(resultQTy));
2382
2383 // Create the appropriate overflow-checked arithmetic operation.
2384 mlir::Location loc = getLoc(e->getSourceRange());
2385 mlir::Value result, overflow;
2386 switch (builtinID) {
2387 default:
2388 llvm_unreachable("Unknown overflow builtin id.");
2389 case Builtin::BI__builtin_uadd_overflow:
2390 case Builtin::BI__builtin_uaddl_overflow:
2391 case Builtin::BI__builtin_uaddll_overflow:
2392 case Builtin::BI__builtin_sadd_overflow:
2393 case Builtin::BI__builtin_saddl_overflow:
2394 case Builtin::BI__builtin_saddll_overflow:
2395 std::tie(result, overflow) =
2396 emitOverflowOp<cir::AddOverflowOp>(builder, loc, resultCIRTy, x, y);
2397 break;
2398 case Builtin::BI__builtin_usub_overflow:
2399 case Builtin::BI__builtin_usubl_overflow:
2400 case Builtin::BI__builtin_usubll_overflow:
2401 case Builtin::BI__builtin_ssub_overflow:
2402 case Builtin::BI__builtin_ssubl_overflow:
2403 case Builtin::BI__builtin_ssubll_overflow:
2404 std::tie(result, overflow) =
2405 emitOverflowOp<cir::SubOverflowOp>(builder, loc, resultCIRTy, x, y);
2406 break;
2407 case Builtin::BI__builtin_umul_overflow:
2408 case Builtin::BI__builtin_umull_overflow:
2409 case Builtin::BI__builtin_umulll_overflow:
2410 case Builtin::BI__builtin_smul_overflow:
2411 case Builtin::BI__builtin_smull_overflow:
2412 case Builtin::BI__builtin_smulll_overflow:
2413 std::tie(result, overflow) =
2414 emitOverflowOp<cir::MulOverflowOp>(builder, loc, resultCIRTy, x, y);
2415 break;
2416 }
2417
2418 bool isVolatile =
2419 resultArg->getType()->getPointeeType().isVolatileQualified();
2420 builder.createStore(loc, emitToMemory(result, resultQTy), resultPtr,
2421 isVolatile);
2422
2423 return RValue::get(overflow);
2424 }
2425
2426 case Builtin::BIaddressof:
2427 case Builtin::BI__addressof:
2428 case Builtin::BI__builtin_addressof:
2429 return RValue::get(emitLValue(e->getArg(0)).getPointer());
2430 case Builtin::BI__builtin_function_start:
2431 return errorBuiltinNYI(*this, e, builtinID);
2432 case Builtin::BI__builtin_operator_new:
2434 e->getCallee()->getType()->castAs<FunctionProtoType>(), e, OO_New);
2435 case Builtin::BI__builtin_operator_delete:
2437 e->getCallee()->getType()->castAs<FunctionProtoType>(), e, OO_Delete);
2438 return RValue::get(nullptr);
2439 case Builtin::BI__builtin_is_aligned:
2440 case Builtin::BI__builtin_align_up:
2441 case Builtin::BI__builtin_align_down:
2442 case Builtin::BI__noop:
2443 case Builtin::BI__builtin_call_with_static_chain:
2444 case Builtin::BI_InterlockedExchange8:
2445 case Builtin::BI_InterlockedExchange16:
2446 case Builtin::BI_InterlockedExchange:
2447 case Builtin::BI_InterlockedExchangePointer:
2448 case Builtin::BI_InterlockedCompareExchangePointer:
2449 case Builtin::BI_InterlockedCompareExchangePointer_nf:
2450 case Builtin::BI_InterlockedCompareExchange8:
2451 case Builtin::BI_InterlockedCompareExchange16:
2452 case Builtin::BI_InterlockedCompareExchange:
2453 case Builtin::BI_InterlockedCompareExchange64:
2454 case Builtin::BI_InterlockedIncrement16:
2455 case Builtin::BI_InterlockedIncrement:
2456 case Builtin::BI_InterlockedDecrement16:
2457 case Builtin::BI_InterlockedDecrement:
2458 case Builtin::BI_InterlockedAnd8:
2459 case Builtin::BI_InterlockedAnd16:
2460 case Builtin::BI_InterlockedAnd:
2461 case Builtin::BI_InterlockedExchangeAdd8:
2462 case Builtin::BI_InterlockedExchangeAdd16:
2463 case Builtin::BI_InterlockedExchangeAdd:
2464 case Builtin::BI_InterlockedExchangeSub8:
2465 case Builtin::BI_InterlockedExchangeSub16:
2466 case Builtin::BI_InterlockedExchangeSub:
2467 case Builtin::BI_InterlockedOr8:
2468 case Builtin::BI_InterlockedOr16:
2469 case Builtin::BI_InterlockedOr:
2470 case Builtin::BI_InterlockedXor8:
2471 case Builtin::BI_InterlockedXor16:
2472 case Builtin::BI_InterlockedXor:
2473 case Builtin::BI_bittest64:
2474 case Builtin::BI_bittest:
2475 case Builtin::BI_bittestandcomplement64:
2476 case Builtin::BI_bittestandcomplement:
2477 case Builtin::BI_bittestandreset64:
2478 case Builtin::BI_bittestandreset:
2479 case Builtin::BI_bittestandset64:
2480 case Builtin::BI_bittestandset:
2481 case Builtin::BI_interlockedbittestandreset:
2482 case Builtin::BI_interlockedbittestandreset64:
2483 case Builtin::BI_interlockedbittestandreset64_acq:
2484 case Builtin::BI_interlockedbittestandreset64_rel:
2485 case Builtin::BI_interlockedbittestandreset64_nf:
2486 case Builtin::BI_interlockedbittestandset64:
2487 case Builtin::BI_interlockedbittestandset64_acq:
2488 case Builtin::BI_interlockedbittestandset64_rel:
2489 case Builtin::BI_interlockedbittestandset64_nf:
2490 case Builtin::BI_interlockedbittestandset:
2491 case Builtin::BI_interlockedbittestandset_acq:
2492 case Builtin::BI_interlockedbittestandset_rel:
2493 case Builtin::BI_interlockedbittestandset_nf:
2494 case Builtin::BI_interlockedbittestandreset_acq:
2495 case Builtin::BI_interlockedbittestandreset_rel:
2496 case Builtin::BI_interlockedbittestandreset_nf:
2497 case Builtin::BI__iso_volatile_load8:
2498 case Builtin::BI__iso_volatile_load16:
2499 case Builtin::BI__iso_volatile_load32:
2500 case Builtin::BI__iso_volatile_load64:
2501 case Builtin::BI__iso_volatile_store8:
2502 case Builtin::BI__iso_volatile_store16:
2503 case Builtin::BI__iso_volatile_store32:
2504 case Builtin::BI__iso_volatile_store64:
2505 case Builtin::BI__builtin_ptrauth_sign_constant:
2506 case Builtin::BI__builtin_ptrauth_auth:
2507 case Builtin::BI__builtin_ptrauth_auth_and_resign:
2508 case Builtin::BI__builtin_ptrauth_blend_discriminator:
2509 case Builtin::BI__builtin_ptrauth_sign_generic_data:
2510 case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
2511 case Builtin::BI__builtin_ptrauth_strip:
2512 case Builtin::BI__builtin_get_vtable_pointer:
2513 case Builtin::BI__exception_code:
2514 case Builtin::BI_exception_code:
2515 case Builtin::BI__exception_info:
2516 case Builtin::BI_exception_info:
2517 case Builtin::BI__abnormal_termination:
2518 case Builtin::BI_abnormal_termination:
2519 return errorBuiltinNYI(*this, e, builtinID);
2520 case Builtin::BI_setjmpex:
2521 case Builtin::BI_setjmp:
2522 if (getTarget().getTriple().isOSMSVCRT()) {
2523 cgm.errorNYI(e->getSourceRange(), "setjmp/setjmpex on MSVCRT");
2524 return getUndefRValue(e->getType());
2525 }
2526 // Else break and this will be handled as a library call.
2527 break;
2528 case Builtin::BImove:
2529 case Builtin::BImove_if_noexcept:
2530 case Builtin::BIforward:
2531 case Builtin::BIforward_like:
2532 case Builtin::BIas_const:
2533 return RValue::get(emitLValue(e->getArg(0)).getPointer());
2534 case Builtin::BI__GetExceptionInfo:
2535 case Builtin::BI__fastfail:
2536 case Builtin::BIread_pipe:
2537 case Builtin::BIwrite_pipe:
2538 case Builtin::BIreserve_read_pipe:
2539 case Builtin::BIreserve_write_pipe:
2540 case Builtin::BIwork_group_reserve_read_pipe:
2541 case Builtin::BIwork_group_reserve_write_pipe:
2542 case Builtin::BIsub_group_reserve_read_pipe:
2543 case Builtin::BIsub_group_reserve_write_pipe:
2544 case Builtin::BIcommit_read_pipe:
2545 case Builtin::BIcommit_write_pipe:
2546 case Builtin::BIwork_group_commit_read_pipe:
2547 case Builtin::BIwork_group_commit_write_pipe:
2548 case Builtin::BIsub_group_commit_read_pipe:
2549 case Builtin::BIsub_group_commit_write_pipe:
2550 case Builtin::BIget_pipe_num_packets:
2551 case Builtin::BIget_pipe_max_packets:
2552 case Builtin::BIto_global:
2553 case Builtin::BIto_local:
2554 case Builtin::BIto_private:
2555 case Builtin::BIenqueue_kernel:
2556 case Builtin::BIget_kernel_work_group_size:
2557 case Builtin::BIget_kernel_preferred_work_group_size_multiple:
2558 case Builtin::BIget_kernel_max_sub_group_size_for_ndrange:
2559 case Builtin::BIget_kernel_sub_group_count_for_ndrange:
2560 case Builtin::BI__builtin_store_half:
2561 case Builtin::BI__builtin_store_halff:
2562 case Builtin::BI__builtin_load_half:
2563 case Builtin::BI__builtin_load_halff:
2564 return errorBuiltinNYI(*this, e, builtinID);
2565 case Builtin::BI__builtin_printf:
2566 case Builtin::BIprintf:
2567 if (getTarget().getTriple().isNVPTX() ||
2568 getTarget().getTriple().isAMDGCN() ||
2569 (getTarget().getTriple().isSPIRV() &&
2570 getTarget().getTriple().getVendor() == llvm::Triple::AMD)) {
2571 if (getTarget().getTriple().isNVPTX())
2573 if ((getTarget().getTriple().isAMDGCN() ||
2574 getTarget().getTriple().isSPIRV()) &&
2575 getLangOpts().HIP)
2576 return errorBuiltinNYI(*this, e, builtinID);
2577 }
2578 break;
2579 case Builtin::BI__builtin_canonicalize:
2580 case Builtin::BI__builtin_canonicalizef:
2581 case Builtin::BI__builtin_canonicalizef16:
2582 case Builtin::BI__builtin_canonicalizel:
2583 case Builtin::BI__builtin_thread_pointer:
2584 case Builtin::BI__builtin_os_log_format:
2585 case Builtin::BI__xray_customevent:
2586 case Builtin::BI__xray_typedevent:
2587 case Builtin::BI__builtin_ms_va_start:
2588 case Builtin::BI__builtin_ms_va_end:
2589 case Builtin::BI__builtin_ms_va_copy:
2590 case Builtin::BI__builtin_get_device_side_mangled_name:
2591 return errorBuiltinNYI(*this, e, builtinID);
2592 }
2593
2594 // If this is an alias for a lib function (e.g. __builtin_sin), emit
2595 // the call using the normal call path, but using the unmangled
2596 // version of the function name.
2597 if (!shouldEmitBuiltinAsIR(builtinID, getContext().BuiltinInfo, *this) &&
2598 getContext().BuiltinInfo.isLibFunction(builtinID))
2599 return emitLibraryCall(*this, fd, e,
2600 cgm.getBuiltinLibFunction(fd, builtinID));
2601
2602 // If this is a predefined lib function (e.g. malloc), emit the call
2603 // using exactly the normal call path.
2604 if (getContext().BuiltinInfo.isPredefinedLibFunction(builtinID))
2605 return emitLibraryCall(*this, fd, e,
2606 emitScalarExpr(e->getCallee()).getDefiningOp());
2607
2608 // See if we have a target specific intrinsic.
2609 std::string name = getContext().BuiltinInfo.getName(builtinID);
2610 Intrinsic::ID intrinsicID = Intrinsic::not_intrinsic;
2611 StringRef prefix =
2612 llvm::Triple::getArchTypePrefix(getTarget().getTriple().getArch());
2613 if (!prefix.empty()) {
2614 intrinsicID = Intrinsic::getIntrinsicForClangBuiltin(prefix, name);
2615 // NOTE we don't need to perform a compatibility flag check here since the
2616 // intrinsics are declared in Builtins*.def via LANGBUILTIN which filter the
2617 // MS builtins via ALL_MS_LANGUAGES and are filtered earlier.
2618 if (intrinsicID == Intrinsic::not_intrinsic)
2619 intrinsicID = Intrinsic::getIntrinsicForMSBuiltin(prefix, name);
2620 }
2621
2622 if (intrinsicID != Intrinsic::not_intrinsic) {
2623 unsigned iceArguments = 0;
2625 getContext().GetBuiltinType(builtinID, error, &iceArguments);
2626 assert(error == ASTContext::GE_None && "Should not codegen an error");
2627
2628 StringRef name = Intrinsic::getName(intrinsicID);
2629 // cir::LLVMIntrinsicCallOp expects intrinsic name to not have prefix
2630 // "llvm." For example, `llvm.nvvm.barrier0` should be passed as
2631 // `nvvm.barrier0`.
2632 assert(name.starts_with("llvm.") && "expected llvm. prefix");
2633 name = name.drop_front(/*strlen("llvm.")=*/5);
2634
2635 cir::FuncType intrinsicType =
2636 getIntrinsicType(*this, &getMLIRContext(), intrinsicID);
2637
2639 const FunctionDecl *fd = e->getDirectCallee();
2640 for (unsigned i = 0; i < e->getNumArgs(); i++) {
2641 mlir::Value argValue =
2642 emitScalarOrConstFoldImmArg(iceArguments, i, e->getArg(i));
2643 // If the intrinsic arg type is different from the builtin arg type
2644 // we need to do a bit cast.
2645 mlir::Type argType = argValue.getType();
2646 mlir::Type expectedTy = intrinsicType.getInput(i);
2647
2648 // Correct integer signedness based on AST parameter type
2649 mlir::Type correctedExpectedTy = expectedTy;
2650 if (fd && i < fd->getNumParams()) {
2651 correctedExpectedTy = correctIntegerSignedness(
2652 expectedTy, fd->getParamDecl(i)->getType(), &getMLIRContext());
2653 }
2654
2655 if (mlir::isa<cir::PointerType>(expectedTy)) {
2656 bool argIsPointer = mlir::isa<cir::PointerType>(argType);
2657 bool argIsVectorOfPointer = false;
2658 if (auto vecTy = dyn_cast<mlir::VectorType>(argType))
2659 argIsVectorOfPointer =
2660 mlir::isa<cir::PointerType>(vecTy.getElementType());
2661
2662 if (!argIsPointer && !argIsVectorOfPointer) {
2663 cgm.errorNYI(
2664 e->getSourceRange(),
2665 "intrinsic expects a pointer type (NYI for non-pointer)");
2666 return getUndefRValue(e->getType());
2667 }
2668
2669 // Pointer handling (address-space cast / bitcast fallback).
2670 if (argType != expectedTy)
2671 argValue = getCorrectedPtr(argValue, expectedTy, builder);
2672 } else {
2673 // Non-pointer expected type: if needed, bitcast to the corrected
2674 // expected type to match signedness/representation.
2675 if (argType != correctedExpectedTy)
2676 argValue = builder.createBitcast(argValue, correctedExpectedTy);
2677 }
2678
2679 args.push_back(argValue);
2680 }
2681
2682 // Correct return type signedness based on AST return type before creating
2683 // the call, avoiding unnecessary casts in the IR.
2684 mlir::Type correctedReturnType = intrinsicType.getReturnType();
2685 if (fd) {
2686 correctedReturnType =
2687 correctIntegerSignedness(intrinsicType.getReturnType(),
2688 fd->getReturnType(), &getMLIRContext());
2689 }
2690
2691 cir::LLVMIntrinsicCallOp intrinsicCall = cir::LLVMIntrinsicCallOp::create(
2692 builder, getLoc(e->getExprLoc()), builder.getStringAttr(name),
2693 correctedReturnType, args);
2694
2695 mlir::Value intrinsicRes = intrinsicCall.getResult();
2696
2697 if (isa<cir::VoidType>(correctedReturnType))
2698 return RValue::get(nullptr);
2699
2700 return RValue::get(intrinsicRes);
2701 }
2702
2703 // Some target-specific builtins can have aggregate return values, e.g.
2704 // __builtin_arm_mve_vld2q_u32. So if the result is an aggregate, force
2705 // returnValue to be non-null, so that the target-specific emission code can
2706 // always just emit into it.
2708 if (evalKind == cir::TEK_Aggregate && returnValue.isNull()) {
2709 cgm.errorNYI(e->getSourceRange(), "aggregate return value from builtin");
2710 return getUndefRValue(e->getType());
2711 }
2712
2713 // Now see if we can emit a target-specific builtin.
2714 // FIXME: This is a temporary mechanism (double-optional semantics) that will
2715 // go away once everything is implemented:
2716 // 1. return `mlir::Value{}` for cases where we have issued the diagnostic.
2717 // 2. return `std::nullopt` in cases where we didn't issue a diagnostic
2718 // but also didn't handle the builtin.
2719 if (std::optional<mlir::Value> rst =
2720 emitTargetBuiltinExpr(builtinID, e, returnValue)) {
2721 mlir::Value v = rst.value();
2722 // CIR dialect operations may have no results, no values will be returned
2723 // even if it executes successfully.
2724 if (!v)
2725 return RValue::get(nullptr);
2726
2727 switch (evalKind) {
2728 case cir::TEK_Scalar:
2729 if (mlir::isa<cir::VoidType>(v.getType()))
2730 return RValue::get(nullptr);
2731 return RValue::get(v);
2732 case cir::TEK_Aggregate:
2733 cgm.errorNYI(e->getSourceRange(), "aggregate return value from builtin");
2734 return getUndefRValue(e->getType());
2735 case cir::TEK_Complex:
2736 llvm_unreachable("No current target builtin returns complex");
2737 }
2738 llvm_unreachable("Bad evaluation kind in EmitBuiltinExpr");
2739 }
2740
2741 cgm.errorNYI(e->getSourceRange(),
2742 std::string("unimplemented builtin call: ") +
2743 getContext().BuiltinInfo.getName(builtinID));
2744 return getUndefRValue(e->getType());
2745}
2746
2747static std::optional<mlir::Value>
2749 const CallExpr *e, ReturnValueSlot &returnValue,
2750 llvm::Triple::ArchType arch) {
2751 // When compiling in HipStdPar mode we have to be conservative in rejecting
2752 // target specific features in the FE, and defer the possible error to the
2753 // AcceleratorCodeSelection pass, wherein iff an unsupported target builtin is
2754 // referenced by an accelerator executable function, we emit an error.
2755 // Returning nullptr here leads to the builtin being handled in
2756 // EmitStdParUnsupportedBuiltin.
2757 if (cgf->getLangOpts().HIPStdPar && cgf->getLangOpts().CUDAIsDevice &&
2758 arch != cgf->getTarget().getTriple().getArch())
2759 return std::nullopt;
2760
2761 switch (arch) {
2762 case llvm::Triple::arm:
2763 case llvm::Triple::armeb:
2764 case llvm::Triple::thumb:
2765 case llvm::Triple::thumbeb:
2766 // These are actually NYI, but that will be reported by emitBuiltinExpr.
2767 // At this point, we don't even know that the builtin is target-specific.
2768 return std::nullopt;
2769 case llvm::Triple::aarch64:
2770 case llvm::Triple::aarch64_32:
2771 case llvm::Triple::aarch64_be:
2772 return cgf->emitAArch64BuiltinExpr(builtinID, e, returnValue, arch);
2773 case llvm::Triple::bpfeb:
2774 case llvm::Triple::bpfel:
2775 // These are actually NYI, but that will be reported by emitBuiltinExpr.
2776 // At this point, we don't even know that the builtin is target-specific.
2777 return std::nullopt;
2778
2779 case llvm::Triple::x86:
2780 case llvm::Triple::x86_64:
2781 return cgf->emitX86BuiltinExpr(builtinID, e);
2782
2783 case llvm::Triple::ppc:
2784 case llvm::Triple::ppcle:
2785 case llvm::Triple::ppc64:
2786 case llvm::Triple::ppc64le:
2787 case llvm::Triple::r600:
2788 // These are actually NYI, but that will be reported by emitBuiltinExpr.
2789 // At this point, we don't even know that the builtin is target-specific.
2790 return std::nullopt;
2791 case llvm::Triple::amdgpu:
2792 return cgf->emitAMDGPUBuiltinExpr(builtinID, e);
2793 case llvm::Triple::systemz:
2794 return std::nullopt;
2795 case llvm::Triple::nvptx:
2796 case llvm::Triple::nvptx64:
2797 return cgf->emitNVPTXBuiltinExpr(builtinID, e);
2798 case llvm::Triple::wasm32:
2799 case llvm::Triple::wasm64:
2800 case llvm::Triple::hexagon:
2801 // These are actually NYI, but that will be reported by emitBuiltinExpr.
2802 // At this point, we don't even know that the builtin is target-specific.
2803 return std::nullopt;
2804 case llvm::Triple::riscv32:
2805 case llvm::Triple::riscv64:
2806 return cgf->emitRISCVBuiltinExpr(builtinID, e);
2807 default:
2808 return std::nullopt;
2809 }
2810}
2811
2812std::optional<mlir::Value>
2815 if (getContext().BuiltinInfo.isAuxBuiltinID(builtinID)) {
2816 assert(getContext().getAuxTargetInfo() && "Missing aux target info");
2818 this, getContext().BuiltinInfo.getAuxBuiltinID(builtinID), e,
2819 returnValue, getContext().getAuxTargetInfo()->getTriple().getArch());
2820 }
2821
2822 return emitTargetArchBuiltinExpr(this, builtinID, e, returnValue,
2823 getTarget().getTriple().getArch());
2824}
2825
2827 const unsigned iceArguments, const unsigned idx, const Expr *argExpr) {
2828 mlir::Value arg = {};
2829 if ((iceArguments & (1 << idx)) == 0) {
2830 arg = emitScalarExpr(argExpr);
2831 } else {
2832 // If this is required to be a constant, constant fold it so that we
2833 // know that the generated intrinsic gets a ConstantInt.
2834 const std::optional<llvm::APSInt> result =
2836 assert(result && "Expected argument to be a constant");
2837 arg = builder.getConstInt(getLoc(argExpr->getSourceRange()), *result);
2838 }
2839 return arg;
2840}
2841
2842/// Given a builtin id for a function like "__builtin_fabsf", return a Function*
2843/// for "fabsf".
2845 unsigned builtinID) {
2846 assert(astContext.BuiltinInfo.isLibFunction(builtinID));
2847
2848 // Get the name, skip over the __builtin_ prefix (if necessary). We may have
2849 // to build this up so provide a small stack buffer to handle the vast
2850 // majority of names.
2852
2854 name = astContext.BuiltinInfo.getName(builtinID).substr(10);
2855
2856 GlobalDecl d(fd);
2857 mlir::Type type = convertType(fd->getType());
2858 return getOrCreateCIRFunction(name, type, d, /*forVTable=*/false);
2859}
2860
2862 mlir::Value argValue = evaluateExprAsBool(e);
2863 if (!sanOpts.has(SanitizerKind::Builtin))
2864 return argValue;
2865
2867 cgm.errorNYI(e->getSourceRange(),
2868 "emitCheckedArgForAssume: sanitizers are NYI");
2869 return {};
2870}
2871
2872void CIRGenFunction::emitVAStart(mlir::Value vaList) {
2873 // LLVM codegen casts to *i8, no real gain on doing this for CIRGen this
2874 // early, defer to LLVM lowering.
2875 cir::VAStartOp::create(builder, vaList.getLoc(), vaList);
2876}
2877
2878void CIRGenFunction::emitVAEnd(mlir::Value vaList) {
2879 cir::VAEndOp::create(builder, vaList.getLoc(), vaList);
2880}
2881
2882// FIXME(cir): This completely abstracts away the ABI with a generic CIR Op. By
2883// default this lowers to llvm.va_arg which is incomplete and not ABI-compliant
2884// on most targets so cir.va_arg will need some ABI handling in LoweringPrepare
2886 assert(!cir::MissingFeatures::msabi());
2887 assert(!cir::MissingFeatures::vlas());
2888 mlir::Location loc = cgm.getLoc(ve->getExprLoc());
2889 mlir::Type type = convertType(ve->getType());
2890 mlir::Value vaList = emitVAListRef(ve->getSubExpr()).getPointer();
2891 return cir::VAArgOp::create(builder, loc, type, vaList);
2892}
2893
2894mlir::Value CIRGenFunction::emitBuiltinObjectSize(const Expr *e, unsigned type,
2895 cir::IntType resType,
2896 mlir::Value emittedE,
2897 bool isDynamic) {
2898 // If this is a pass_object_size parameter, load the implicit size arg.
2899 //
2900 // BOS type compatibility: a pass_object_size annotation with one type can
2901 // satisfy a __builtin_object_size query with a different type when the
2902 // annotated type is a safe approximation. Type 0 (max, whole object) is
2903 // an overestimate for type 1 (max, closest surrounding subobject), and
2904 // type 3 (min, closest surrounding subobject) is an underestimate for
2905 // type 2 (min, whole object).
2906 enum BOSType {
2907 MaxWholeObject = 0,
2908 MaxSubobject = 1,
2909 MinWholeObject = 2,
2910 MinSubobject = 3,
2911 };
2912 if (auto *dre = dyn_cast<DeclRefExpr>(e->IgnoreParenImpCasts())) {
2913 auto *param = dyn_cast<ParmVarDecl>(dre->getDecl());
2914 auto *objSizeAttr = dre->getDecl()->getAttr<PassObjectSizeAttr>();
2915 if (param && objSizeAttr) {
2916 auto from = objSizeAttr->getType();
2917 bool compatible = from == static_cast<int>(type) ||
2918 (from == MaxWholeObject && type == MaxSubobject) ||
2919 (from == MinSubobject && type == MinWholeObject);
2920 if (compatible) {
2921 const ImplicitParamDecl *sizeDecl = sizeArguments.lookup(param);
2922 assert(sizeDecl && "expected pass_object_size implicit param");
2923
2924 DeclMapTy::iterator declIter = localDeclMap.find(sizeDecl);
2925 assert(declIter != localDeclMap.end());
2926 Address addr = declIter->second;
2927
2928 return emitLoadOfScalar(addr, /*volatile=*/false,
2929 getContext().getSizeType(), e->getBeginLoc(),
2931 }
2932 }
2933 }
2934
2935 // LLVM can't handle type=3 appropriately, and __builtin_object_size shouldn't
2936 // evaluate e for side-effects. In either case, just like original LLVM
2937 // lowering, we shouldn't lower to `cir.objsize` but to a constant instead.
2938 if (type == 3 || (!emittedE && e->HasSideEffects(getContext())))
2939 return builder.getConstInt(getLoc(e->getSourceRange()), resType,
2940 (type & 2) ? 0 : -1);
2941
2942 mlir::Value ptr = emittedE ? emittedE : emitScalarExpr(e);
2943 assert(mlir::isa<cir::PointerType>(ptr.getType()) &&
2944 "Non-pointer passed to __builtin_object_size?");
2945
2947
2948 // Extract the min/max mode from type. CIR only supports type 0
2949 // (max, whole object) and type 2 (min, whole object), not type 1 or 3
2950 // (closest subobject variants).
2951 const bool min = ((type & 2) != 0);
2952 // For GCC compatibility, __builtin_object_size treats NULL as unknown size.
2953 auto op =
2954 cir::ObjSizeOp::create(builder, getLoc(e->getSourceRange()), resType, ptr,
2955 min, /*nullUnknown=*/true, isDynamic);
2956 return op.getResult();
2957}
2958
2960 const Expr *e, unsigned type, cir::IntType resType, mlir::Value emittedE,
2961 bool isDynamic) {
2962 if (std::optional<uint64_t> objectSize =
2964 return builder.getConstInt(getLoc(e->getSourceRange()), resType,
2965 *objectSize);
2966 return emitBuiltinObjectSize(e, type, resType, emittedE, isDynamic);
2967}
static StringRef bytes(const std::vector< T, Allocator > &v)
Defines enum values for all the target-independent builtin functions.
static mlir::Value emitSignBit(mlir::Location loc, CIRGenFunction &cgf, mlir::Value val)
static mlir::Value emitBinaryMaybeConstrainedFPBuiltin(CIRGenFunction &cgf, const CallExpr &e)
static mlir::Value createBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e, mlir::Value arg, Args... args)
static mlir::Type decodeFixedType(CIRGenFunction &cgf, ArrayRef< llvm::Intrinsic::IITDescriptor > &infos, mlir::MLIRContext *context)
static RValue emitUnaryMaybeConstrainedFPBuiltin(CIRGenFunction &cgf, const CallExpr &e)
static RValue emitBinaryFPBuiltin(CIRGenFunction &cgf, const CallExpr &e)
static RValue emitBinaryAtomicPost(CIRGenFunction &cgf, cir::AtomicFetchKind atomicOpkind, const CallExpr *e, bool invert=false)
static std::optional< mlir::Value > emitTargetArchBuiltinExpr(CIRGenFunction *cgf, unsigned builtinID, const CallExpr *e, ReturnValueSlot &returnValue, llvm::Triple::ArchType arch)
static RValue emitUnaryFPBuiltin(CIRGenFunction &cgf, const CallExpr &e)
static RValue emitBinaryAtomic(CIRGenFunction &cgf, cir::AtomicFetchKind atomicOpkind, const CallExpr *e)
static mlir::Value emitToInt(CIRGenFunction &cgf, mlir::Value v, QualType t, cir::IntType intType)
Emit the conversions required to turn the given value into an integer of the given size.
static mlir::Value getCorrectedPtr(mlir::Value argValue, mlir::Type expectedTy, CIRGenBuilderTy &builder)
static std::pair< mlir::Value, mlir::Value > emitOverflowOp(CIRGenBuilderTy &builder, mlir::Location loc, mlir::Type resultTy, mlir::Value lhs, mlir::Value rhs)
Create a checked overflow arithmetic op and return its result and overflow flag.
static bool shouldEmitBuiltinAsIR(unsigned builtinID, const Builtin::Context &bi, const CIRGenFunction &cgf)
static RValue emitTernaryMaybeConstrainedFPBuiltin(CIRGenFunction &cgf, const CallExpr &e)
static RValue emitLibraryCall(CIRGenFunction &cgf, const FunctionDecl *fd, const CallExpr *e, mlir::Operation *calleeValue)
static WidthAndSignedness getIntegerWidthAndSignedness(const clang::ASTContext &astContext, const clang::QualType type)
static void emitAtomicFenceOp(CIRGenFunction &cgf, const CallExpr *expr, cir::SyncScopeKind syncScope)
static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e, Args... args)
static Address checkAtomicAlignment(CIRGenFunction &cgf, const CallExpr *e)
static RValue emitAtomicIsLockFree(CIRGenFunction &cgf, const CallExpr *e, unsigned builtinID)
static bool shouldCIREmitFPMathIntrinsic(CIRGenFunction &cgf, const CallExpr *e, unsigned builtinID)
static RValue tryEmitFPMathIntrinsic(CIRGenFunction &cgf, const CallExpr *e, unsigned builtinID)
static RValue emitBuiltinBitOpWithFallback(CIRGenFunction &cgf, const CallExpr *e)
Emit a clz/ctz bit op with optional fallback for __builtin_c[lt]zg.
static cir::FuncType getIntrinsicType(CIRGenFunction &cgf, mlir::MLIRContext *context, llvm::Intrinsic::ID id)
static struct WidthAndSignedness EncompassingIntegerType(ArrayRef< struct WidthAndSignedness > types)
static RValue emitBuiltinAlloca(CIRGenFunction &cgf, const CallExpr *e, unsigned builtinID)
static mlir::Type correctIntegerSignedness(mlir::Type iitType, QualType astType, mlir::MLIRContext *context)
Helper function to correct integer signedness for intrinsic arguments and return type.
static RValue emitUnaryMaybeConstrainedFPToIntBuiltin(CIRGenFunction &cgf, const CallExpr &e)
static RValue errorBuiltinNYI(CIRGenFunction &cgf, const CallExpr *e, unsigned builtinID)
static mlir::Value emitFromInt(CIRGenFunction &cgf, mlir::Value v, QualType t, mlir::Type resultType)
static StringRef getTriple(const Command &Job)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
Defines an enumeration for C++ overloaded operators.
static QualType getPointeeType(const MemRegion *R)
__DEVICE__ int min(int __a, int __b)
cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc)
cir::SignBitOp createSignBit(mlir::Location loc, mlir::Value val)
mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy)
mlir::Value createPtrToInt(mlir::Value src, mlir::Type newTy)
cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc)
mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, llvm::StringRef name, mlir::IntegerAttr alignment, mlir::Value dynAllocSize)
mlir::Value createIntCast(mlir::Value src, mlir::Type newTy)
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
mlir::Value createNot(mlir::Location loc, mlir::Value value)
mlir::Value createSelect(mlir::Location loc, mlir::Value condition, mlir::Value trueValue, mlir::Value falseValue)
cir::PointerType getVoidPtrTy(clang::LangAS langAS=clang::LangAS::Default)
mlir::Value createAddrSpaceCast(mlir::Location loc, mlir::Value src, mlir::Type newTy)
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, mlir::Type returnType, mlir::ValueRange operands, llvm::ArrayRef< mlir::NamedAttribute > attrs={}, llvm::ArrayRef< mlir::NamedAttrList > argAttrs={}, llvm::ArrayRef< mlir::NamedAttribute > resAttrs={})
cir::BoolType getBoolTy()
llvm::TypeSize getTypeSizeInBits(mlir::Type ty) const
APSInt & getInt()
Definition APValue.h:511
bool isFloat() const
Definition APValue.h:489
bool isInt() const
Definition APValue.h:488
APFloat & getFloat()
Definition APValue.h:525
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
unsigned getIntWidth(QualType T) const
CanQualType VoidPtrTy
Builtin::Context & BuiltinInfo
Definition ASTContext.h:810
TypeInfo getTypeInfo(const Type *T) const
Get the size and alignment of the specified complete type in bits.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error, unsigned *IntegerConstantArgs=nullptr) const
Return the type for the specified builtin.
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:927
CharUnits toCharUnitsFromBits(int64_t BitSize) const
Convert a size in bits to a size in characters.
static bool hasSameUnqualifiedType(QualType T1, QualType T2)
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
@ GE_None
No error.
uint64_t getCharWidth() const
Return the size of the character type, in bits.
Holds information about both target-independent and target-specific builtins, allowing easy queries b...
Definition Builtins.h:236
bool shouldGenerateFPMathIntrinsic(unsigned BuiltinID, llvm::Triple Trip, std::optional< bool > ErrnoOverwritten, bool MathErrnoEnabled, bool HasOptNoneAttr, bool IsOptimizationEnabled) const
Determine whether we can generate LLVM intrinsics for the given builtin ID, based on whether it has s...
Definition Builtins.cpp:242
bool isLibFunction(unsigned ID) const
Return true if this is a builtin for a libc/libm function, with a "__builtin_" prefix (e....
Definition Builtins.h:310
std::string getName(unsigned ID) const
Return the identifier name for the specified builtin, e.g.
Definition Builtins.cpp:94
mlir::Value getPointer() const
Definition Address.h:98
mlir::Type getElementType() const
Definition Address.h:125
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const
Return address with different element type, a bitcast pointer, and the same alignment.
clang::CharUnits getAlignment() const
Definition Address.h:138
Address withAlignment(clang::CharUnits newAlignment) const
Return address with different alignment, but same pointer and element type.
Definition Address.h:89
mlir::Value emitRawPointer() const
Return the pointer contained in this class after authenticating it and adding offset to it if necessa...
Definition Address.h:112
cir::PointerType getUInt8PtrTy()
static CIRGenCallee forDirect(mlir::Operation *funcPtr, const CIRGenCalleeInfo &abstractInfo=CIRGenCalleeInfo())
Definition CIRGenCall.h:92
mlir::Type convertType(clang::QualType t)
mlir::Value emitCheckedArgForAssume(const Expr *e)
Emits an argument for a call to a __builtin_assume.
static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type)
Return the cir::TypeEvaluationKind of QualType type.
Address emitPointerWithAlignment(const clang::Expr *expr, LValueBaseInfo *baseInfo=nullptr)
Given an expression with a pointer type, emit the value and compute our best estimate of the alignmen...
const clang::LangOptions & getLangOpts() const
void emitTrap(mlir::Location loc, bool createNewBlock)
Emit a trap instruction, which is used to abort the program in an abnormal way, usually for debugging...
mlir::Value emitComplexExpr(const Expr *e)
Emit the computation of the specified expression of complex type, returning the result.
const TargetInfo & getTarget() const
LValue emitLValue(const clang::Expr *e)
Emit code to compute a designator that specifies the location of the expression.
const clang::Decl * curFuncDecl
mlir::Value evaluateExprAsBool(const clang::Expr *e)
Perform the usual unary conversions on the specified expression and compare the result against zero,...
LValue makeNaturalAlignAddrLValue(mlir::Value val, QualType ty)
mlir::Value emitNVPTXDevicePrintfCallExpr(const CallExpr *expr)
Emit a device-side printf call for NVPTX targets.
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
cir::CallOp emitCoroFreeBuiltin(const CallExpr *e)
mlir::Value evaluateOrEmitBuiltinObjectSize(const clang::Expr *e, unsigned type, cir::IntType resType, mlir::Value emittedE, bool isDynamic)
std::optional< mlir::Value > emitRISCVBuiltinExpr(unsigned builtinID, const CallExpr *expr)
mlir::Value emitBuiltinObjectSize(const clang::Expr *e, unsigned type, cir::IntType resType, mlir::Value emittedE, bool isDynamic)
Returns a Value corresponding to the size of the given expression by emitting a cir....
mlir::Value makeBinaryAtomicValue(cir::AtomicFetchKind kind, const clang::CallExpr *expr, mlir::Type *originalArgType=nullptr, mlir::Value *emittedArgValue=nullptr, cir::MemOrder ordering=cir::MemOrder::SequentiallyConsistent)
Utility to insert an atomic instruction based on Intrinsic::ID and the expression node.
std::optional< mlir::Value > emitTargetBuiltinExpr(unsigned builtinID, const clang::CallExpr *e, ReturnValueSlot &returnValue)
clang::SanitizerSet sanOpts
Sanitizers enabled for this function.
void emitUnreachable(clang::SourceLocation loc, bool createNewBlock)
Emit a reached-unreachable diagnostic if loc is valid and runtime checking is enabled.
void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile, clang::QualType ty, LValueBaseInfo baseInfo, bool isInit=false, bool isNontemporal=false)
RValue getUndefRValue(clang::QualType ty)
Get an appropriate 'undef' rvalue for the given type.
Address returnValue
The temporary alloca to hold the return value.
std::optional< mlir::Value > emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr)
RValue emitCall(const CIRGenFunctionInfo &funcInfo, const CIRGenCallee &callee, ReturnValueSlot returnValue, const CallArgList &args, cir::CIRCallOpInterface *callOp, mlir::Location loc)
RValue emitBuiltinWithOneOverloadedType(const CallExpr *e, llvm::StringRef intrinName, mlir::Type resultType={})
Emit a simple LLVM intrinsic that takes N scalar arguments.
std::optional< mlir::Value > emitAMDGPUBuiltinExpr(unsigned builtinID, const CallExpr *expr)
Emit a call to an AMDGPU builtin function.
std::optional< mlir::Value > emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr, ReturnValueSlot returnValue, llvm::Triple::ArchType arch)
void emitAtomicExprWithMemOrder(const Expr *memOrder, bool isStore, bool isLoad, bool isFence, llvm::function_ref< void(cir::MemOrder)> emitAtomicOp)
llvm::SmallDenseMap< const ParmVarDecl *, const ImplicitParamDecl * > sizeArguments
If a ParmVarDecl had the pass_object_size attribute, this will contain a mapping from said ParmVarDec...
void emitVAEnd(mlir::Value vaList)
Emits the end of a CIR variable-argument operation (cir.va_start)
mlir::Value emitToMemory(mlir::Value value, clang::QualType ty)
Given a value and its clang type, returns the value casted to its memory representation.
mlir::Value emitScalarExpr(const clang::Expr *e, bool ignoreResultAssign=false)
Emit the computation of the specified expression of scalar type.
CIRGenBuilderTy & getBuilder()
void emitVAStart(mlir::Value vaList)
Emits the start of a CIR variable-argument operation (cir.va_start)
void emitNonNullArgCheck(RValue rv, QualType argType, SourceLocation argLoc, AbstractCallee ac, unsigned paramNum)
Create a check for a function parameter that may potentially be declared as non-null.
mlir::MLIRContext & getMLIRContext()
mlir::Value emitLoadOfScalar(LValue lvalue, SourceLocation loc)
EmitLoadOfScalar - Load a scalar value from an address, taking care to appropriately convert from the...
DeclMapTy localDeclMap
This keeps track of the CIR allocas or globals for local C declarations.
std::optional< mlir::Value > emitNVPTXBuiltinExpr(unsigned builtinID, const CallExpr *expr)
Emit a call to an NVPTX builtin function.
mlir::Value emitAlignmentAssumption(mlir::Value ptrValue, QualType ty, SourceLocation loc, SourceLocation assumptionLoc, int64_t alignment, mlir::Value offsetValue=nullptr)
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
RValue emitNewOrDeleteBuiltinCall(const FunctionProtoType *type, const CallExpr *callExpr, OverloadedOperatorKind op)
CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder, bool suppressNewContext=false)
clang::ASTContext & getContext() const
RValue emitBuiltinExpr(const clang::GlobalDecl &gd, unsigned builtinID, const clang::CallExpr *e, ReturnValueSlot returnValue)
mlir::Value emitFromMemory(mlir::Value value, clang::QualType ty)
EmitFromMemory - Change a scalar value from its memory representation to its value representation.
Address emitVAListRef(const Expr *e)
Build a "reference" to a va_list; this is either the address or the value of the expression,...
mlir::Value emitScalarOrConstFoldImmArg(unsigned iceArguments, unsigned idx, const Expr *argExpr)
mlir::Value emitVAArg(VAArgExpr *ve)
Generate code to get an argument from the passed in pointer and update it accordingly.
RValue emitRotate(const CallExpr *e, bool isRotateLeft)
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
clang::ASTContext & getASTContext() const
mlir::Type convertType(clang::QualType type)
clang::DiagnosticsEngine & getDiags() const
cir::FuncOp getBuiltinLibFunction(const FunctionDecl *fd, unsigned builtinID)
Given a builtin id for a function like "__builtin_fabsf", return a Function* for "fabsf".
const llvm::Triple & getTriple() const
cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name, mlir::NamedAttrList extraAttrs={}, bool isLocal=false, bool assumeConvergent=false)
const cir::CIRDataLayout getDataLayout() const
const clang::CodeGenOptions & getCodeGenOpts() const
const clang::LangOptions & getLangOpts() const
cir::FuncOp getOrCreateCIRFunction(llvm::StringRef mangledName, mlir::Type funcType, clang::GlobalDecl gd, bool forVTable, bool dontDefer=false, bool isThunk=false, ForDefinition_t isForDefinition=NotForDefinition, mlir::NamedAttrList extraAttrs={})
const TargetCIRGenInfo & getTargetCIRGenInfo()
mlir::Value getPointer() const
void setNontemporal(bool v)
This trivial value class is used to represent the result of an expression that is evaluated.
Definition CIRGenValue.h:33
static RValue get(mlir::Value v)
Definition CIRGenValue.h:83
static RValue getComplex(mlir::Value v)
Definition CIRGenValue.h:91
bool isIgnored() const
Definition CIRGenValue.h:52
static RValue getIgnored()
Definition CIRGenValue.h:78
Contains the address where the return value of a function can be stored, and whether the address is v...
Definition CIRGenCall.h:260
virtual bool supportsLibCall() const
Returns true if the target supports math library calls.
Definition TargetInfo.h:54
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2949
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3153
bool hasStoredFPFeatures() const
Definition Expr.h:3108
SourceLocation getBeginLoc() const
Definition Expr.h:3283
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3132
Expr * getCallee()
Definition Expr.h:3096
FPOptionsOverride getFPFeatures() const
Definition Expr.h:3248
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3140
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
CharUnits alignmentAtOffset(CharUnits offset) const
Given that this is a non-zero alignment value, what is the alignment at the given offset?
Definition CharUnits.h:207
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
Definition DeclBase.cpp:273
bool hasAttr() const
Definition DeclBase.h:585
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:234
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
This represents one expression.
Definition Expr.h:112
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3101
bool EvaluateAsFloat(llvm::APFloat &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsFloat - Return true if this is a constant which we can fold and convert to a floating point...
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
bool isPRValue() const
Definition Expr.h:285
bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsRValue - Return true if this is a constant which we can fold to an rvalue using any crazy t...
bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const
HasSideEffects - This routine returns true for all those expressions which have any effect other than...
Definition Expr.cpp:3699
std::optional< uint64_t > tryEvaluateObjectSize(const ASTContext &Ctx, unsigned Type) const
If the current Expr is a pointer, this will try to statically determine the number of bytes available...
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
QualType getType() const
Definition Expr.h:144
Represents difference between two FPOptions values.
LangOptions::FPExceptionModeKind getExceptionMode() const
Represents a function declaration or definition.
Definition Decl.h:2029
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2837
QualType getReturnType() const
Definition Decl.h:2885
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5406
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:57
const Decl * getDecl() const
Definition GlobalDecl.h:106
@ FPE_Ignore
Assume that floating-point exceptions are masked.
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3393
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isVolatileQualified() const
Determine whether this type is volatile-qualified.
Definition TypeBase.h:8573
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8615
bool requiresBuiltinLaunder(const ASTContext &Context) const
Returns true if this type requires laundering by checking if it is a dynamic class type,...
Definition Type.cpp:5619
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:355
Exposes information about the current target.
Definition TargetInfo.h:227
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
virtual bool isCLZForZeroUndef() const
The __builtin_clz* and __builtin_ctz* built-in functions are specified to have undefined results for ...
unsigned getSuitableAlign() const
Return the alignment that is the largest alignment ever used for any scalar/SIMD data type on the tar...
Definition TargetInfo.h:751
bool isBlockPointerType() const
Definition TypeBase.h:8746
bool isBooleanType() const
Definition TypeBase.h:9229
bool isPointerType() const
Definition TypeBase.h:8726
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9386
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Definition TypeBase.h:9214
bool isExtVectorBoolType() const
Definition TypeBase.h:8873
bool isObjCObjectPointerType() const
Definition TypeBase.h:8905
bool isFloatingType() const
Definition Type.cpp:2393
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
Definition Type.cpp:2336
Represents a call to the builtin function __builtin_va_arg.
Definition Expr.h:4963
const Expr * getSubExpr() const
Definition Expr.h:4983
QualType getType() const
Definition Decl.h:723
bool isMatchingAddressSpace(mlir::ptr::MemorySpaceAttrInterface cirAS, clang::LangAS as)
@ Type
The l-value was considered opaque, so the alignment was determined from a type.
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
U cast(CodeGen::Address addr)
Definition Address.h:327
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
static bool builtinCheckKind()
static bool addressSpace()
static bool asmLabelAttr()
static bool msvcBuiltins()
static bool builtinCallF128()
static bool isPPC_FP128Ty()
static bool emitCheckedInBoundsGEP()
static bool fpConstraints()
static bool countedBySize()
static bool fastMathFlags()
static bool builtinBitCountExpr()
static bool builtinCall()
static bool generateDebugInfo()
cir::PointerType allocaInt8PtrTy
void* in alloca address space
mlir::ptr::MemorySpaceAttrInterface getCIRAllocaAddressSpace() const
cir::PointerType voidPtrTy
void* in address space 0
EvalResult is a struct with detailed info about an evaluated expression.
Definition Expr.h:652
APValue Val
Val - This is the value the expression can be folded to.
Definition Expr.h:654
bool hasSideEffects() const
Return true if the evaluated expression has side effects.
Definition Expr.h:646
#define conj(__x)
Definition tgmath.h:1303