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