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