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