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