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