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