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