clang 22.0.0git
CIRGenExprScalar.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// Emit Expr nodes with scalar CIR types as CIR code.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenFunction.h"
14#include "CIRGenValue.h"
15
16#include "clang/AST/Expr.h"
19
20#include "mlir/IR/Location.h"
21#include "mlir/IR/Value.h"
22
23#include <cassert>
24#include <utility>
25
26using namespace clang;
27using namespace clang::CIRGen;
28
29namespace {
30
31struct BinOpInfo {
32 mlir::Value lhs;
33 mlir::Value rhs;
34 SourceRange loc;
35 QualType fullType; // Type of operands and result
36 QualType compType; // Type used for computations. Element type
37 // for vectors, otherwise same as FullType.
38 BinaryOperator::Opcode opcode; // Opcode of BinOp to perform
39 FPOptions fpfeatures;
40 const Expr *e; // Entire expr, for error unsupported. May not be binop.
41
42 /// Check if the binop computes a division or a remainder.
43 bool isDivRemOp() const {
44 return opcode == BO_Div || opcode == BO_Rem || opcode == BO_DivAssign ||
45 opcode == BO_RemAssign;
46 }
47
48 /// Check if the binop can result in integer overflow.
49 bool mayHaveIntegerOverflow() const {
50 // Without constant input, we can't rule out overflow.
51 auto lhsci = lhs.getDefiningOp<cir::ConstantOp>();
52 auto rhsci = rhs.getDefiningOp<cir::ConstantOp>();
53 if (!lhsci || !rhsci)
54 return true;
55
57 // TODO(cir): For now we just assume that we might overflow
58 return true;
59 }
60
61 /// Check if at least one operand is a fixed point type. In such cases,
62 /// this operation did not follow usual arithmetic conversion and both
63 /// operands might not be of the same type.
64 bool isFixedPointOp() const {
65 // We cannot simply check the result type since comparison operations
66 // return an int.
67 if (const auto *binOp = llvm::dyn_cast<BinaryOperator>(e)) {
68 QualType lhstype = binOp->getLHS()->getType();
69 QualType rhstype = binOp->getRHS()->getType();
70 return lhstype->isFixedPointType() || rhstype->isFixedPointType();
71 }
72 if (const auto *unop = llvm::dyn_cast<UnaryOperator>(e))
73 return unop->getSubExpr()->getType()->isFixedPointType();
74 return false;
75 }
76};
77
78class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
79 CIRGenFunction &cgf;
80 CIRGenBuilderTy &builder;
81 bool ignoreResultAssign;
82
83public:
84 ScalarExprEmitter(CIRGenFunction &cgf, CIRGenBuilderTy &builder)
85 : cgf(cgf), builder(builder) {}
86
87 //===--------------------------------------------------------------------===//
88 // Utilities
89 //===--------------------------------------------------------------------===//
90
91 mlir::Value emitComplexToScalarConversion(mlir::Location loc,
92 mlir::Value value, CastKind kind,
93 QualType destTy);
94
95 mlir::Value emitNullValue(QualType ty, mlir::Location loc) {
96 return cgf.cgm.emitNullConstant(ty, loc);
97 }
98
99 mlir::Value emitPromotedValue(mlir::Value result, QualType promotionType) {
100 return builder.createFloatingCast(result, cgf.convertType(promotionType));
101 }
102
103 mlir::Value emitUnPromotedValue(mlir::Value result, QualType exprType) {
104 return builder.createFloatingCast(result, cgf.convertType(exprType));
105 }
106
107 mlir::Value emitPromoted(const Expr *e, QualType promotionType);
108
109 mlir::Value maybePromoteBoolResult(mlir::Value value,
110 mlir::Type dstTy) const {
111 if (mlir::isa<cir::IntType>(dstTy))
112 return builder.createBoolToInt(value, dstTy);
113 if (mlir::isa<cir::BoolType>(dstTy))
114 return value;
115 llvm_unreachable("Can only promote integer or boolean types");
116 }
117
118 //===--------------------------------------------------------------------===//
119 // Visitor Methods
120 //===--------------------------------------------------------------------===//
121
122 mlir::Value Visit(Expr *e) {
124 }
125
126 mlir::Value VisitStmt(Stmt *s) {
127 llvm_unreachable("Statement passed to ScalarExprEmitter");
128 }
129
130 mlir::Value VisitExpr(Expr *e) {
132 e->getSourceRange(), "scalar expression kind: ", e->getStmtClassName());
133 return {};
134 }
135
136 mlir::Value VisitPackIndexingExpr(PackIndexingExpr *e) {
137 return Visit(e->getSelectedExpr());
138 }
139
140 mlir::Value VisitParenExpr(ParenExpr *pe) { return Visit(pe->getSubExpr()); }
141
142 mlir::Value VisitGenericSelectionExpr(GenericSelectionExpr *ge) {
143 return Visit(ge->getResultExpr());
144 }
145
146 /// Emits the address of the l-value, then loads and returns the result.
147 mlir::Value emitLoadOfLValue(const Expr *e) {
148 LValue lv = cgf.emitLValue(e);
149 // FIXME: add some akin to EmitLValueAlignmentAssumption(E, V);
150 return cgf.emitLoadOfLValue(lv, e->getExprLoc()).getValue();
151 }
152
153 mlir::Value emitLoadOfLValue(LValue lv, SourceLocation loc) {
154 return cgf.emitLoadOfLValue(lv, loc).getValue();
155 }
156
157 // l-values
158 mlir::Value VisitDeclRefExpr(DeclRefExpr *e) {
160 return cgf.emitScalarConstant(constant, e);
161
162 return emitLoadOfLValue(e);
163 }
164
165 mlir::Value VisitIntegerLiteral(const IntegerLiteral *e) {
166 mlir::Type type = cgf.convertType(e->getType());
167 return builder.create<cir::ConstantOp>(
168 cgf.getLoc(e->getExprLoc()), cir::IntAttr::get(type, e->getValue()));
169 }
170
171 mlir::Value VisitFloatingLiteral(const FloatingLiteral *e) {
172 mlir::Type type = cgf.convertType(e->getType());
173 assert(mlir::isa<cir::FPTypeInterface>(type) &&
174 "expect floating-point type");
175 return builder.create<cir::ConstantOp>(
176 cgf.getLoc(e->getExprLoc()), cir::FPAttr::get(type, e->getValue()));
177 }
178
179 mlir::Value VisitCharacterLiteral(const CharacterLiteral *e) {
180 mlir::Type ty = cgf.convertType(e->getType());
181 auto init = cir::IntAttr::get(ty, e->getValue());
182 return builder.create<cir::ConstantOp>(cgf.getLoc(e->getExprLoc()), init);
183 }
184
185 mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
186 return builder.getBool(e->getValue(), cgf.getLoc(e->getExprLoc()));
187 }
188
189 mlir::Value VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *e) {
190 if (e->getType()->isVoidType())
191 return {};
192
193 return emitNullValue(e->getType(), cgf.getLoc(e->getSourceRange()));
194 }
195
196 mlir::Value VisitCastExpr(CastExpr *e);
197 mlir::Value VisitCallExpr(const CallExpr *e);
198
199 mlir::Value VisitStmtExpr(StmtExpr *e) {
201 if (e->getType()->isVoidType()) {
202 (void)cgf.emitCompoundStmt(*e->getSubStmt());
203 return {};
204 }
205
206 Address retAlloca =
207 cgf.createMemTemp(e->getType(), cgf.getLoc(e->getSourceRange()));
208 (void)cgf.emitCompoundStmt(*e->getSubStmt(), &retAlloca);
209
210 return cgf.emitLoadOfScalar(cgf.makeAddrLValue(retAlloca, e->getType()),
211 e->getExprLoc());
212 }
213
214 mlir::Value VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
215 if (e->getBase()->getType()->isVectorType()) {
217
218 const mlir::Location loc = cgf.getLoc(e->getSourceRange());
219 const mlir::Value vecValue = Visit(e->getBase());
220 const mlir::Value indexValue = Visit(e->getIdx());
221 return cgf.builder.create<cir::VecExtractOp>(loc, vecValue, indexValue);
222 }
223 // Just load the lvalue formed by the subscript expression.
224 return emitLoadOfLValue(e);
225 }
226
227 mlir::Value VisitShuffleVectorExpr(ShuffleVectorExpr *e) {
228 if (e->getNumSubExprs() == 2) {
229 // The undocumented form of __builtin_shufflevector.
230 mlir::Value inputVec = Visit(e->getExpr(0));
231 mlir::Value indexVec = Visit(e->getExpr(1));
232 return cgf.builder.create<cir::VecShuffleDynamicOp>(
233 cgf.getLoc(e->getSourceRange()), inputVec, indexVec);
234 }
235
236 mlir::Value vec1 = Visit(e->getExpr(0));
237 mlir::Value vec2 = Visit(e->getExpr(1));
238
239 // The documented form of __builtin_shufflevector, where the indices are
240 // a variable number of integer constants. The constants will be stored
241 // in an ArrayAttr.
243 for (unsigned i = 2; i < e->getNumSubExprs(); ++i) {
244 indices.push_back(
245 cir::IntAttr::get(cgf.builder.getSInt64Ty(),
246 e->getExpr(i)
248 .getSExtValue()));
249 }
250
251 return cgf.builder.create<cir::VecShuffleOp>(
252 cgf.getLoc(e->getSourceRange()), cgf.convertType(e->getType()), vec1,
253 vec2, cgf.builder.getArrayAttr(indices));
254 }
255
256 mlir::Value VisitConvertVectorExpr(ConvertVectorExpr *e) {
257 // __builtin_convertvector is an element-wise cast, and is implemented as a
258 // regular cast. The back end handles casts of vectors correctly.
259 return emitScalarConversion(Visit(e->getSrcExpr()),
260 e->getSrcExpr()->getType(), e->getType(),
261 e->getSourceRange().getBegin());
262 }
263
264 mlir::Value VisitMemberExpr(MemberExpr *e);
265
266 mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
267 return emitLoadOfLValue(e);
268 }
269
270 mlir::Value VisitInitListExpr(InitListExpr *e);
271
272 mlir::Value VisitExplicitCastExpr(ExplicitCastExpr *e) {
273 return VisitCastExpr(e);
274 }
275
276 mlir::Value VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *e) {
277 return cgf.cgm.emitNullConstant(e->getType(),
278 cgf.getLoc(e->getSourceRange()));
279 }
280
281 /// Perform a pointer to boolean conversion.
282 mlir::Value emitPointerToBoolConversion(mlir::Value v, QualType qt) {
283 // TODO(cir): comparing the ptr to null is done when lowering CIR to LLVM.
284 // We might want to have a separate pass for these types of conversions.
285 return cgf.getBuilder().createPtrToBoolCast(v);
286 }
287
288 mlir::Value emitFloatToBoolConversion(mlir::Value src, mlir::Location loc) {
289 cir::BoolType boolTy = builder.getBoolTy();
290 return builder.create<cir::CastOp>(loc, boolTy,
291 cir::CastKind::float_to_bool, src);
292 }
293
294 mlir::Value emitIntToBoolConversion(mlir::Value srcVal, mlir::Location loc) {
295 // Because of the type rules of C, we often end up computing a
296 // logical value, then zero extending it to int, then wanting it
297 // as a logical value again.
298 // TODO: optimize this common case here or leave it for later
299 // CIR passes?
300 cir::BoolType boolTy = builder.getBoolTy();
301 return builder.create<cir::CastOp>(loc, boolTy, cir::CastKind::int_to_bool,
302 srcVal);
303 }
304
305 /// Convert the specified expression value to a boolean (!cir.bool) truth
306 /// value. This is equivalent to "Val != 0".
307 mlir::Value emitConversionToBool(mlir::Value src, QualType srcType,
308 mlir::Location loc) {
309 assert(srcType.isCanonical() && "EmitScalarConversion strips typedefs");
310
311 if (srcType->isRealFloatingType())
312 return emitFloatToBoolConversion(src, loc);
313
314 if (llvm::isa<MemberPointerType>(srcType)) {
315 cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
316 return builder.getFalse(loc);
317 }
318
319 if (srcType->isIntegerType())
320 return emitIntToBoolConversion(src, loc);
321
322 assert(::mlir::isa<cir::PointerType>(src.getType()));
323 return emitPointerToBoolConversion(src, srcType);
324 }
325
326 // Emit a conversion from the specified type to the specified destination
327 // type, both of which are CIR scalar types.
328 struct ScalarConversionOpts {
329 bool treatBooleanAsSigned;
330 bool emitImplicitIntegerTruncationChecks;
331 bool emitImplicitIntegerSignChangeChecks;
332
333 ScalarConversionOpts()
334 : treatBooleanAsSigned(false),
335 emitImplicitIntegerTruncationChecks(false),
336 emitImplicitIntegerSignChangeChecks(false) {}
337
338 ScalarConversionOpts(clang::SanitizerSet sanOpts)
339 : treatBooleanAsSigned(false),
340 emitImplicitIntegerTruncationChecks(
341 sanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)),
342 emitImplicitIntegerSignChangeChecks(
343 sanOpts.has(SanitizerKind::ImplicitIntegerSignChange)) {}
344 };
345
346 // Conversion from bool, integral, or floating-point to integral or
347 // floating-point. Conversions involving other types are handled elsewhere.
348 // Conversion to bool is handled elsewhere because that's a comparison against
349 // zero, not a simple cast. This handles both individual scalars and vectors.
350 mlir::Value emitScalarCast(mlir::Value src, QualType srcType,
351 QualType dstType, mlir::Type srcTy,
352 mlir::Type dstTy, ScalarConversionOpts opts) {
353 assert(!srcType->isMatrixType() && !dstType->isMatrixType() &&
354 "Internal error: matrix types not handled by this function.");
355 assert(!(mlir::isa<mlir::IntegerType>(srcTy) ||
356 mlir::isa<mlir::IntegerType>(dstTy)) &&
357 "Obsolete code. Don't use mlir::IntegerType with CIR.");
358
359 mlir::Type fullDstTy = dstTy;
360 if (mlir::isa<cir::VectorType>(srcTy) &&
361 mlir::isa<cir::VectorType>(dstTy)) {
362 // Use the element types of the vectors to figure out the CastKind.
363 srcTy = mlir::dyn_cast<cir::VectorType>(srcTy).getElementType();
364 dstTy = mlir::dyn_cast<cir::VectorType>(dstTy).getElementType();
365 }
366
367 std::optional<cir::CastKind> castKind;
368
369 if (mlir::isa<cir::BoolType>(srcTy)) {
370 if (opts.treatBooleanAsSigned)
371 cgf.getCIRGenModule().errorNYI("signed bool");
372 if (cgf.getBuilder().isInt(dstTy))
373 castKind = cir::CastKind::bool_to_int;
374 else if (mlir::isa<cir::FPTypeInterface>(dstTy))
375 castKind = cir::CastKind::bool_to_float;
376 else
377 llvm_unreachable("Internal error: Cast to unexpected type");
378 } else if (cgf.getBuilder().isInt(srcTy)) {
379 if (cgf.getBuilder().isInt(dstTy))
380 castKind = cir::CastKind::integral;
381 else if (mlir::isa<cir::FPTypeInterface>(dstTy))
382 castKind = cir::CastKind::int_to_float;
383 else
384 llvm_unreachable("Internal error: Cast to unexpected type");
385 } else if (mlir::isa<cir::FPTypeInterface>(srcTy)) {
386 if (cgf.getBuilder().isInt(dstTy)) {
387 // If we can't recognize overflow as undefined behavior, assume that
388 // overflow saturates. This protects against normal optimizations if we
389 // are compiling with non-standard FP semantics.
390 if (!cgf.cgm.getCodeGenOpts().StrictFloatCastOverflow)
391 cgf.getCIRGenModule().errorNYI("strict float cast overflow");
393 castKind = cir::CastKind::float_to_int;
394 } else if (mlir::isa<cir::FPTypeInterface>(dstTy)) {
395 // TODO: split this to createFPExt/createFPTrunc
396 return builder.createFloatingCast(src, fullDstTy);
397 } else {
398 llvm_unreachable("Internal error: Cast to unexpected type");
399 }
400 } else {
401 llvm_unreachable("Internal error: Cast from unexpected type");
402 }
403
404 assert(castKind.has_value() && "Internal error: CastKind not set.");
405 return builder.create<cir::CastOp>(src.getLoc(), fullDstTy, *castKind, src);
406 }
407
408 mlir::Value
409 VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e) {
410 return Visit(e->getReplacement());
411 }
412
413 mlir::Value VisitVAArgExpr(VAArgExpr *ve) {
414 QualType ty = ve->getType();
415
416 if (ty->isVariablyModifiedType()) {
417 cgf.cgm.errorNYI(ve->getSourceRange(),
418 "variably modified types in varargs");
419 }
420
421 return cgf.emitVAArg(ve);
422 }
423
424 mlir::Value VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *e);
425 mlir::Value
426 VisitAbstractConditionalOperator(const AbstractConditionalOperator *e);
427
428 // Unary Operators.
429 mlir::Value VisitUnaryPostDec(const UnaryOperator *e) {
430 LValue lv = cgf.emitLValue(e->getSubExpr());
431 return emitScalarPrePostIncDec(e, lv, cir::UnaryOpKind::Dec, false);
432 }
433 mlir::Value VisitUnaryPostInc(const UnaryOperator *e) {
434 LValue lv = cgf.emitLValue(e->getSubExpr());
435 return emitScalarPrePostIncDec(e, lv, cir::UnaryOpKind::Inc, false);
436 }
437 mlir::Value VisitUnaryPreDec(const UnaryOperator *e) {
438 LValue lv = cgf.emitLValue(e->getSubExpr());
439 return emitScalarPrePostIncDec(e, lv, cir::UnaryOpKind::Dec, true);
440 }
441 mlir::Value VisitUnaryPreInc(const UnaryOperator *e) {
442 LValue lv = cgf.emitLValue(e->getSubExpr());
443 return emitScalarPrePostIncDec(e, lv, cir::UnaryOpKind::Inc, true);
444 }
445 mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv,
446 cir::UnaryOpKind kind, bool isPre) {
447 if (cgf.getLangOpts().OpenMP)
448 cgf.cgm.errorNYI(e->getSourceRange(), "inc/dec OpenMP");
449
451
452 mlir::Value value;
453 mlir::Value input;
454
455 if (type->getAs<AtomicType>()) {
456 cgf.cgm.errorNYI(e->getSourceRange(), "Atomic inc/dec");
457 // TODO(cir): This is not correct, but it will produce reasonable code
458 // until atomic operations are implemented.
459 value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getValue();
460 input = value;
461 } else {
462 value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getValue();
463 input = value;
464 }
465
466 // NOTE: When possible, more frequent cases are handled first.
467
468 // Special case of integer increment that we have to check first: bool++.
469 // Due to promotion rules, we get:
470 // bool++ -> bool = bool + 1
471 // -> bool = (int)bool + 1
472 // -> bool = ((int)bool + 1 != 0)
473 // An interesting aspect of this is that increment is always true.
474 // Decrement does not have this property.
475 if (kind == cir::UnaryOpKind::Inc && type->isBooleanType()) {
476 value = builder.getTrue(cgf.getLoc(e->getExprLoc()));
477 } else if (type->isIntegerType()) {
478 QualType promotedType;
479 [[maybe_unused]] bool canPerformLossyDemotionCheck = false;
481 promotedType = cgf.getContext().getPromotedIntegerType(type);
482 assert(promotedType != type && "Shouldn't promote to the same type.");
483 canPerformLossyDemotionCheck = true;
484 canPerformLossyDemotionCheck &=
486 cgf.getContext().getCanonicalType(promotedType);
487 canPerformLossyDemotionCheck &=
488 type->isIntegerType() && promotedType->isIntegerType();
489
490 // TODO(cir): Currently, we store bitwidths in CIR types only for
491 // integers. This might also be required for other types.
492
493 assert(
494 (!canPerformLossyDemotionCheck ||
495 type->isSignedIntegerOrEnumerationType() ||
496 promotedType->isSignedIntegerOrEnumerationType() ||
497 mlir::cast<cir::IntType>(cgf.convertType(type)).getWidth() ==
498 mlir::cast<cir::IntType>(cgf.convertType(type)).getWidth()) &&
499 "The following check expects that if we do promotion to different "
500 "underlying canonical type, at least one of the types (either "
501 "base or promoted) will be signed, or the bitwidths will match.");
502 }
503
505 if (e->canOverflow() && type->isSignedIntegerOrEnumerationType()) {
506 value = emitIncDecConsiderOverflowBehavior(e, value, kind);
507 } else {
508 cir::UnaryOpKind kind =
509 e->isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;
510 // NOTE(CIR): clang calls CreateAdd but folds this to a unary op
511 value = emitUnaryOp(e, kind, input, /*nsw=*/false);
512 }
513 } else if (const PointerType *ptr = type->getAs<PointerType>()) {
514 QualType type = ptr->getPointeeType();
516 // VLA types don't have constant size.
517 cgf.cgm.errorNYI(e->getSourceRange(), "Pointer arithmetic on VLA");
518 return {};
519 } else if (type->isFunctionType()) {
520 // Arithmetic on function pointers (!) is just +-1.
521 cgf.cgm.errorNYI(e->getSourceRange(),
522 "Pointer arithmetic on function pointer");
523 return {};
524 } else {
525 // For everything else, we can just do a simple increment.
526 mlir::Location loc = cgf.getLoc(e->getSourceRange());
527 CIRGenBuilderTy &builder = cgf.getBuilder();
528 int amount = kind == cir::UnaryOpKind::Inc ? 1 : -1;
529 mlir::Value amt = builder.getSInt32(amount, loc);
531 value = builder.createPtrStride(loc, value, amt);
532 }
533 } else if (type->isVectorType()) {
534 cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec vector");
535 return {};
536 } else if (type->isRealFloatingType()) {
538
539 if (type->isHalfType() &&
540 !cgf.getContext().getLangOpts().NativeHalfType) {
541 cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec half");
542 return {};
543 }
544
545 if (mlir::isa<cir::SingleType, cir::DoubleType>(value.getType())) {
546 // Create the inc/dec operation.
547 // NOTE(CIR): clang calls CreateAdd but folds this to a unary op
548 assert(kind == cir::UnaryOpKind::Inc ||
549 kind == cir::UnaryOpKind::Dec && "Invalid UnaryOp kind");
550 value = emitUnaryOp(e, kind, value);
551 } else {
552 cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec other fp type");
553 return {};
554 }
555 } else if (type->isFixedPointType()) {
556 cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec other fixed point");
557 return {};
558 } else {
559 assert(type->castAs<ObjCObjectPointerType>());
560 cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec ObjectiveC pointer");
561 return {};
562 }
563
565 cgf, cgf.getLoc(e->getSourceRange())};
566
567 // Store the updated result through the lvalue
568 if (lv.isBitField())
569 return cgf.emitStoreThroughBitfieldLValue(RValue::get(value), lv);
570 else
571 cgf.emitStoreThroughLValue(RValue::get(value), lv);
572
573 // If this is a postinc, return the value read from memory, otherwise use
574 // the updated value.
575 return isPre ? value : input;
576 }
577
578 mlir::Value emitIncDecConsiderOverflowBehavior(const UnaryOperator *e,
579 mlir::Value inVal,
580 cir::UnaryOpKind kind) {
581 assert(kind == cir::UnaryOpKind::Inc ||
582 kind == cir::UnaryOpKind::Dec && "Invalid UnaryOp kind");
583 switch (cgf.getLangOpts().getSignedOverflowBehavior()) {
585 return emitUnaryOp(e, kind, inVal, /*nsw=*/false);
588 return emitUnaryOp(e, kind, inVal, /*nsw=*/true);
590 if (!e->canOverflow())
591 return emitUnaryOp(e, kind, inVal, /*nsw=*/true);
592 cgf.cgm.errorNYI(e->getSourceRange(), "inc/def overflow SOB_Trapping");
593 return {};
594 }
595 llvm_unreachable("Unexpected signed overflow behavior kind");
596 }
597
598 mlir::Value VisitUnaryAddrOf(const UnaryOperator *e) {
599 if (llvm::isa<MemberPointerType>(e->getType())) {
600 cgf.cgm.errorNYI(e->getSourceRange(), "Address of member pointer");
601 return builder.getNullPtr(cgf.convertType(e->getType()),
602 cgf.getLoc(e->getExprLoc()));
603 }
604
605 return cgf.emitLValue(e->getSubExpr()).getPointer();
606 }
607
608 mlir::Value VisitUnaryDeref(const UnaryOperator *e) {
609 if (e->getType()->isVoidType())
610 return Visit(e->getSubExpr()); // the actual value should be unused
611 return emitLoadOfLValue(e);
612 }
613
614 mlir::Value VisitUnaryPlus(const UnaryOperator *e) {
615 return emitUnaryPlusOrMinus(e, cir::UnaryOpKind::Plus);
616 }
617
618 mlir::Value VisitUnaryMinus(const UnaryOperator *e) {
619 return emitUnaryPlusOrMinus(e, cir::UnaryOpKind::Minus);
620 }
621
622 mlir::Value emitUnaryPlusOrMinus(const UnaryOperator *e,
623 cir::UnaryOpKind kind) {
624 ignoreResultAssign = false;
625
626 QualType promotionType = getPromotionType(e->getSubExpr()->getType());
627
628 mlir::Value operand;
629 if (!promotionType.isNull())
630 operand = cgf.emitPromotedScalarExpr(e->getSubExpr(), promotionType);
631 else
632 operand = Visit(e->getSubExpr());
633
634 bool nsw =
635 kind == cir::UnaryOpKind::Minus && e->getType()->isSignedIntegerType();
636
637 // NOTE: LLVM codegen will lower this directly to either a FNeg
638 // or a Sub instruction. In CIR this will be handled later in LowerToLLVM.
639 mlir::Value result = emitUnaryOp(e, kind, operand, nsw);
640 if (result && !promotionType.isNull())
641 return emitUnPromotedValue(result, e->getType());
642 return result;
643 }
644
645 mlir::Value emitUnaryOp(const UnaryOperator *e, cir::UnaryOpKind kind,
646 mlir::Value input, bool nsw = false) {
647 return builder.create<cir::UnaryOp>(
648 cgf.getLoc(e->getSourceRange().getBegin()), input.getType(), kind,
649 input, nsw);
650 }
651
652 mlir::Value VisitUnaryNot(const UnaryOperator *e) {
653 ignoreResultAssign = false;
654 mlir::Value op = Visit(e->getSubExpr());
655 return emitUnaryOp(e, cir::UnaryOpKind::Not, op);
656 }
657
658 mlir::Value VisitUnaryLNot(const UnaryOperator *e);
659
660 mlir::Value VisitUnaryReal(const UnaryOperator *e);
661
662 mlir::Value VisitUnaryImag(const UnaryOperator *e);
663
664 mlir::Value VisitCXXThisExpr(CXXThisExpr *te) { return cgf.loadCXXThis(); }
665
666 mlir::Value VisitExprWithCleanups(ExprWithCleanups *e);
667 mlir::Value VisitCXXNewExpr(const CXXNewExpr *e) {
668 return cgf.emitCXXNewExpr(e);
669 }
670
671 mlir::Value VisitCXXThrowExpr(const CXXThrowExpr *e) {
672 cgf.emitCXXThrowExpr(e);
673 return {};
674 }
675
676 /// Emit a conversion from the specified type to the specified destination
677 /// type, both of which are CIR scalar types.
678 /// TODO: do we need ScalarConversionOpts here? Should be done in another
679 /// pass.
680 mlir::Value
681 emitScalarConversion(mlir::Value src, QualType srcType, QualType dstType,
682 SourceLocation loc,
683 ScalarConversionOpts opts = ScalarConversionOpts()) {
684 // All conversions involving fixed point types should be handled by the
685 // emitFixedPoint family functions. This is done to prevent bloating up
686 // this function more, and although fixed point numbers are represented by
687 // integers, we do not want to follow any logic that assumes they should be
688 // treated as integers.
689 // TODO(leonardchan): When necessary, add another if statement checking for
690 // conversions to fixed point types from other types.
691 // conversions to fixed point types from other types.
692 if (srcType->isFixedPointType() || dstType->isFixedPointType()) {
693 cgf.getCIRGenModule().errorNYI(loc, "fixed point conversions");
694 return {};
695 }
696
697 srcType = srcType.getCanonicalType();
698 dstType = dstType.getCanonicalType();
699 if (srcType == dstType) {
700 if (opts.emitImplicitIntegerSignChangeChecks)
701 cgf.getCIRGenModule().errorNYI(loc,
702 "implicit integer sign change checks");
703 return src;
704 }
705
706 if (dstType->isVoidType())
707 return {};
708
709 mlir::Type mlirSrcType = src.getType();
710
711 // Handle conversions to bool first, they are special: comparisons against
712 // 0.
713 if (dstType->isBooleanType())
714 return emitConversionToBool(src, srcType, cgf.getLoc(loc));
715
716 mlir::Type mlirDstType = cgf.convertType(dstType);
717
718 if (srcType->isHalfType() &&
719 !cgf.getContext().getLangOpts().NativeHalfType) {
720 // Cast to FP using the intrinsic if the half type itself isn't supported.
721 if (mlir::isa<cir::FPTypeInterface>(mlirDstType)) {
723 cgf.getCIRGenModule().errorNYI(loc,
724 "cast via llvm.convert.from.fp16");
725 } else {
726 // Cast to other types through float, using either the intrinsic or
727 // FPExt, depending on whether the half type itself is supported (as
728 // opposed to operations on half, available with NativeHalfType).
730 cgf.getCIRGenModule().errorNYI(loc,
731 "cast via llvm.convert.from.fp16");
732 // FIXME(cir): For now lets pretend we shouldn't use the conversion
733 // intrinsics and insert a cast here unconditionally.
734 src = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, src,
735 cgf.FloatTy);
736 srcType = cgf.getContext().FloatTy;
737 mlirSrcType = cgf.FloatTy;
738 }
739 }
740
741 // TODO(cir): LLVM codegen ignore conversions like int -> uint,
742 // is there anything to be done for CIR here?
743 if (mlirSrcType == mlirDstType) {
744 if (opts.emitImplicitIntegerSignChangeChecks)
745 cgf.getCIRGenModule().errorNYI(loc,
746 "implicit integer sign change checks");
747 return src;
748 }
749
750 // Handle pointer conversions next: pointers can only be converted to/from
751 // other pointers and integers. Check for pointer types in terms of LLVM, as
752 // some native types (like Obj-C id) may map to a pointer type.
753 if (auto dstPT = dyn_cast<cir::PointerType>(mlirDstType)) {
754 cgf.getCIRGenModule().errorNYI(loc, "pointer casts");
755 return builder.getNullPtr(dstPT, src.getLoc());
756 }
757
758 if (isa<cir::PointerType>(mlirSrcType)) {
759 // Must be an ptr to int cast.
760 assert(isa<cir::IntType>(mlirDstType) && "not ptr->int?");
761 return builder.createPtrToInt(src, mlirDstType);
762 }
763
764 // A scalar can be splatted to an extended vector of the same element type
765 if (dstType->isExtVectorType() && !srcType->isVectorType()) {
766 // Sema should add casts to make sure that the source expression's type
767 // is the same as the vector's element type (sans qualifiers)
768 assert(dstType->castAs<ExtVectorType>()->getElementType().getTypePtr() ==
769 srcType.getTypePtr() &&
770 "Splatted expr doesn't match with vector element type?");
771
772 cgf.getCIRGenModule().errorNYI(loc, "vector splatting");
773 return {};
774 }
775
776 if (srcType->isMatrixType() && dstType->isMatrixType()) {
777 cgf.getCIRGenModule().errorNYI(loc,
778 "matrix type to matrix type conversion");
779 return {};
780 }
781 assert(!srcType->isMatrixType() && !dstType->isMatrixType() &&
782 "Internal error: conversion between matrix type and scalar type");
783
784 // Finally, we have the arithmetic types or vectors of arithmetic types.
785 mlir::Value res = nullptr;
786 mlir::Type resTy = mlirDstType;
787
788 res = emitScalarCast(src, srcType, dstType, mlirSrcType, mlirDstType, opts);
789
790 if (mlirDstType != resTy) {
792 cgf.getCIRGenModule().errorNYI(loc, "cast via llvm.convert.to.fp16");
793 }
794 // FIXME(cir): For now we never use FP16 conversion intrinsics even if
795 // required by the target. Change that once this is implemented
796 res = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, res,
797 resTy);
798 }
799
800 if (opts.emitImplicitIntegerTruncationChecks)
801 cgf.getCIRGenModule().errorNYI(loc, "implicit integer truncation checks");
802
803 if (opts.emitImplicitIntegerSignChangeChecks)
804 cgf.getCIRGenModule().errorNYI(loc,
805 "implicit integer sign change checks");
806
807 return res;
808 }
809
810 BinOpInfo emitBinOps(const BinaryOperator *e,
811 QualType promotionType = QualType()) {
812 BinOpInfo result;
813 result.lhs = cgf.emitPromotedScalarExpr(e->getLHS(), promotionType);
814 result.rhs = cgf.emitPromotedScalarExpr(e->getRHS(), promotionType);
815 if (!promotionType.isNull())
816 result.fullType = promotionType;
817 else
818 result.fullType = e->getType();
819 result.compType = result.fullType;
820 if (const auto *vecType = dyn_cast_or_null<VectorType>(result.fullType)) {
821 result.compType = vecType->getElementType();
822 }
823 result.opcode = e->getOpcode();
824 result.loc = e->getSourceRange();
825 // TODO(cir): Result.FPFeatures
827 result.e = e;
828 return result;
829 }
830
831 mlir::Value emitMul(const BinOpInfo &ops);
832 mlir::Value emitDiv(const BinOpInfo &ops);
833 mlir::Value emitRem(const BinOpInfo &ops);
834 mlir::Value emitAdd(const BinOpInfo &ops);
835 mlir::Value emitSub(const BinOpInfo &ops);
836 mlir::Value emitShl(const BinOpInfo &ops);
837 mlir::Value emitShr(const BinOpInfo &ops);
838 mlir::Value emitAnd(const BinOpInfo &ops);
839 mlir::Value emitXor(const BinOpInfo &ops);
840 mlir::Value emitOr(const BinOpInfo &ops);
841
842 LValue emitCompoundAssignLValue(
843 const CompoundAssignOperator *e,
844 mlir::Value (ScalarExprEmitter::*f)(const BinOpInfo &),
845 mlir::Value &result);
846 mlir::Value
847 emitCompoundAssign(const CompoundAssignOperator *e,
848 mlir::Value (ScalarExprEmitter::*f)(const BinOpInfo &));
849
850 // TODO(cir): Candidate to be in a common AST helper between CIR and LLVM
851 // codegen.
852 QualType getPromotionType(QualType ty) {
853 if (ty->getAs<ComplexType>()) {
855 cgf.cgm.errorNYI("promotion to complex type");
856 return QualType();
857 }
858 if (ty.UseExcessPrecision(cgf.getContext())) {
859 if (ty->getAs<VectorType>()) {
861 cgf.cgm.errorNYI("promotion to vector type");
862 return QualType();
863 }
864 return cgf.getContext().FloatTy;
865 }
866 return QualType();
867 }
868
869// Binary operators and binary compound assignment operators.
870#define HANDLEBINOP(OP) \
871 mlir::Value VisitBin##OP(const BinaryOperator *e) { \
872 QualType promotionTy = getPromotionType(e->getType()); \
873 auto result = emit##OP(emitBinOps(e, promotionTy)); \
874 if (result && !promotionTy.isNull()) \
875 result = emitUnPromotedValue(result, e->getType()); \
876 return result; \
877 } \
878 mlir::Value VisitBin##OP##Assign(const CompoundAssignOperator *e) { \
879 return emitCompoundAssign(e, &ScalarExprEmitter::emit##OP); \
880 }
881
882 HANDLEBINOP(Mul)
883 HANDLEBINOP(Div)
884 HANDLEBINOP(Rem)
885 HANDLEBINOP(Add)
886 HANDLEBINOP(Sub)
887 HANDLEBINOP(Shl)
888 HANDLEBINOP(Shr)
890 HANDLEBINOP(Xor)
892#undef HANDLEBINOP
893
894 mlir::Value emitCmp(const BinaryOperator *e) {
895 const mlir::Location loc = cgf.getLoc(e->getExprLoc());
896 mlir::Value result;
897 QualType lhsTy = e->getLHS()->getType();
898 QualType rhsTy = e->getRHS()->getType();
899
900 auto clangCmpToCIRCmp =
901 [](clang::BinaryOperatorKind clangCmp) -> cir::CmpOpKind {
902 switch (clangCmp) {
903 case BO_LT:
904 return cir::CmpOpKind::lt;
905 case BO_GT:
906 return cir::CmpOpKind::gt;
907 case BO_LE:
908 return cir::CmpOpKind::le;
909 case BO_GE:
910 return cir::CmpOpKind::ge;
911 case BO_EQ:
912 return cir::CmpOpKind::eq;
913 case BO_NE:
914 return cir::CmpOpKind::ne;
915 default:
916 llvm_unreachable("unsupported comparison kind for cir.cmp");
917 }
918 };
919
920 cir::CmpOpKind kind = clangCmpToCIRCmp(e->getOpcode());
921 if (lhsTy->getAs<MemberPointerType>()) {
923 assert(e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE);
924 mlir::Value lhs = cgf.emitScalarExpr(e->getLHS());
925 mlir::Value rhs = cgf.emitScalarExpr(e->getRHS());
926 result = builder.createCompare(loc, kind, lhs, rhs);
927 } else if (!lhsTy->isAnyComplexType() && !rhsTy->isAnyComplexType()) {
928 BinOpInfo boInfo = emitBinOps(e);
929 mlir::Value lhs = boInfo.lhs;
930 mlir::Value rhs = boInfo.rhs;
931
932 if (lhsTy->isVectorType()) {
933 if (!e->getType()->isVectorType()) {
934 // If AltiVec, the comparison results in a numeric type, so we use
935 // intrinsics comparing vectors and giving 0 or 1 as a result
936 cgf.cgm.errorNYI(loc, "AltiVec comparison");
937 } else {
938 // Other kinds of vectors. Element-wise comparison returning
939 // a vector.
940 result = builder.create<cir::VecCmpOp>(
941 cgf.getLoc(boInfo.loc), cgf.convertType(boInfo.fullType), kind,
942 boInfo.lhs, boInfo.rhs);
943 }
944 } else if (boInfo.isFixedPointOp()) {
946 cgf.cgm.errorNYI(loc, "fixed point comparisons");
947 result = builder.getBool(false, loc);
948 } else {
949 // integers and pointers
950 if (cgf.cgm.getCodeGenOpts().StrictVTablePointers &&
951 mlir::isa<cir::PointerType>(lhs.getType()) &&
952 mlir::isa<cir::PointerType>(rhs.getType())) {
953 cgf.cgm.errorNYI(loc, "strict vtable pointer comparisons");
954 }
955
956 cir::CmpOpKind kind = clangCmpToCIRCmp(e->getOpcode());
957 result = builder.createCompare(loc, kind, lhs, rhs);
958 }
959 } else {
960 // Complex Comparison: can only be an equality comparison.
961 assert(e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE);
962
963 BinOpInfo boInfo = emitBinOps(e);
964 result = builder.create<cir::CmpOp>(loc, kind, boInfo.lhs, boInfo.rhs);
965 }
966
967 return emitScalarConversion(result, cgf.getContext().BoolTy, e->getType(),
968 e->getExprLoc());
969 }
970
971// Comparisons.
972#define VISITCOMP(CODE) \
973 mlir::Value VisitBin##CODE(const BinaryOperator *E) { return emitCmp(E); }
975 VISITCOMP(GT)
976 VISITCOMP(LE)
977 VISITCOMP(GE)
978 VISITCOMP(EQ)
979 VISITCOMP(NE)
980#undef VISITCOMP
981
982 mlir::Value VisitBinAssign(const BinaryOperator *e) {
983 const bool ignore = std::exchange(ignoreResultAssign, false);
984
985 mlir::Value rhs;
986 LValue lhs;
987
988 switch (e->getLHS()->getType().getObjCLifetime()) {
994 break;
996 // __block variables need to have the rhs evaluated first, plus this
997 // should improve codegen just a little.
998 rhs = Visit(e->getRHS());
1000 // TODO(cir): This needs to be emitCheckedLValue() once we support
1001 // sanitizers
1002 lhs = cgf.emitLValue(e->getLHS());
1003
1004 // Store the value into the LHS. Bit-fields are handled specially because
1005 // the result is altered by the store, i.e., [C99 6.5.16p1]
1006 // 'An assignment expression has the value of the left operand after the
1007 // assignment...'.
1008 if (lhs.isBitField()) {
1009 rhs = cgf.emitStoreThroughBitfieldLValue(RValue::get(rhs), lhs);
1010 } else {
1011 cgf.emitNullabilityCheck(lhs, rhs, e->getExprLoc());
1013 cgf, cgf.getLoc(e->getSourceRange())};
1014 cgf.emitStoreThroughLValue(RValue::get(rhs), lhs);
1015 }
1016 }
1017
1018 // If the result is clearly ignored, return now.
1019 if (ignore)
1020 return nullptr;
1021
1022 // The result of an assignment in C is the assigned r-value.
1023 if (!cgf.getLangOpts().CPlusPlus)
1024 return rhs;
1025
1026 // If the lvalue is non-volatile, return the computed value of the
1027 // assignment.
1028 if (!lhs.isVolatile())
1029 return rhs;
1030
1031 // Otherwise, reload the value.
1032 return emitLoadOfLValue(lhs, e->getExprLoc());
1033 }
1034
1035 mlir::Value VisitBinComma(const BinaryOperator *e) {
1036 cgf.emitIgnoredExpr(e->getLHS());
1037 // NOTE: We don't need to EnsureInsertPoint() like LLVM codegen.
1038 return Visit(e->getRHS());
1039 }
1040
1041 mlir::Value VisitBinLAnd(const clang::BinaryOperator *e) {
1042 if (e->getType()->isVectorType()) {
1044 return {};
1045 }
1046
1048 mlir::Type resTy = cgf.convertType(e->getType());
1049 mlir::Location loc = cgf.getLoc(e->getExprLoc());
1050
1052
1053 mlir::Value lhsCondV = cgf.evaluateExprAsBool(e->getLHS());
1054 auto resOp = builder.create<cir::TernaryOp>(
1055 loc, lhsCondV, /*trueBuilder=*/
1056 [&](mlir::OpBuilder &b, mlir::Location loc) {
1057 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1058 b.getInsertionBlock()};
1060 b.create<cir::YieldOp>(loc, cgf.evaluateExprAsBool(e->getRHS()));
1061 },
1062 /*falseBuilder*/
1063 [&](mlir::OpBuilder &b, mlir::Location loc) {
1064 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1065 b.getInsertionBlock()};
1067 auto res = b.create<cir::ConstantOp>(loc, builder.getFalseAttr());
1068 b.create<cir::YieldOp>(loc, res.getRes());
1069 });
1070 return maybePromoteBoolResult(resOp.getResult(), resTy);
1071 }
1072
1073 mlir::Value VisitBinLOr(const clang::BinaryOperator *e) {
1074 if (e->getType()->isVectorType()) {
1076 return {};
1077 }
1078
1080 mlir::Type resTy = cgf.convertType(e->getType());
1081 mlir::Location loc = cgf.getLoc(e->getExprLoc());
1082
1084
1085 mlir::Value lhsCondV = cgf.evaluateExprAsBool(e->getLHS());
1086 auto resOp = builder.create<cir::TernaryOp>(
1087 loc, lhsCondV, /*trueBuilder=*/
1088 [&](mlir::OpBuilder &b, mlir::Location loc) {
1089 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1090 b.getInsertionBlock()};
1092 auto res = b.create<cir::ConstantOp>(loc, builder.getTrueAttr());
1093 b.create<cir::YieldOp>(loc, res.getRes());
1094 },
1095 /*falseBuilder*/
1096 [&](mlir::OpBuilder &b, mlir::Location loc) {
1097 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1098 b.getInsertionBlock()};
1100 b.create<cir::YieldOp>(loc, cgf.evaluateExprAsBool(e->getRHS()));
1101 });
1102
1103 return maybePromoteBoolResult(resOp.getResult(), resTy);
1104 }
1105
1106 mlir::Value VisitAtomicExpr(AtomicExpr *e) {
1107 return cgf.emitAtomicExpr(e).getValue();
1108 }
1109};
1110
1111LValue ScalarExprEmitter::emitCompoundAssignLValue(
1112 const CompoundAssignOperator *e,
1113 mlir::Value (ScalarExprEmitter::*func)(const BinOpInfo &),
1114 mlir::Value &result) {
1116 return cgf.emitScalarCompoundAssignWithComplex(e, result);
1117
1118 QualType lhsTy = e->getLHS()->getType();
1119 BinOpInfo opInfo;
1120
1121 // Emit the RHS first. __block variables need to have the rhs evaluated
1122 // first, plus this should improve codegen a little.
1123
1124 QualType promotionTypeCR = getPromotionType(e->getComputationResultType());
1125 if (promotionTypeCR.isNull())
1126 promotionTypeCR = e->getComputationResultType();
1127
1128 QualType promotionTypeLHS = getPromotionType(e->getComputationLHSType());
1129 QualType promotionTypeRHS = getPromotionType(e->getRHS()->getType());
1130
1131 if (!promotionTypeRHS.isNull())
1132 opInfo.rhs = cgf.emitPromotedScalarExpr(e->getRHS(), promotionTypeRHS);
1133 else
1134 opInfo.rhs = Visit(e->getRHS());
1135
1136 opInfo.fullType = promotionTypeCR;
1137 opInfo.compType = opInfo.fullType;
1138 if (const auto *vecType = dyn_cast_or_null<VectorType>(opInfo.fullType))
1139 opInfo.compType = vecType->getElementType();
1140 opInfo.opcode = e->getOpcode();
1141 opInfo.fpfeatures = e->getFPFeaturesInEffect(cgf.getLangOpts());
1142 opInfo.e = e;
1143 opInfo.loc = e->getSourceRange();
1144
1145 // Load/convert the LHS
1146 LValue lhsLV = cgf.emitLValue(e->getLHS());
1147
1148 if (lhsTy->getAs<AtomicType>()) {
1149 cgf.cgm.errorNYI(result.getLoc(), "atomic lvalue assign");
1150 return LValue();
1151 }
1152
1153 opInfo.lhs = emitLoadOfLValue(lhsLV, e->getExprLoc());
1154
1156 cgf, cgf.getLoc(e->getSourceRange())};
1157 SourceLocation loc = e->getExprLoc();
1158 if (!promotionTypeLHS.isNull())
1159 opInfo.lhs = emitScalarConversion(opInfo.lhs, lhsTy, promotionTypeLHS, loc);
1160 else
1161 opInfo.lhs = emitScalarConversion(opInfo.lhs, lhsTy,
1162 e->getComputationLHSType(), loc);
1163
1164 // Expand the binary operator.
1165 result = (this->*func)(opInfo);
1166
1167 // Convert the result back to the LHS type,
1168 // potentially with Implicit Conversion sanitizer check.
1169 result = emitScalarConversion(result, promotionTypeCR, lhsTy, loc,
1170 ScalarConversionOpts(cgf.sanOpts));
1171
1172 // Store the result value into the LHS lvalue. Bit-fields are handled
1173 // specially because the result is altered by the store, i.e., [C99 6.5.16p1]
1174 // 'An assignment expression has the value of the left operand after the
1175 // assignment...'.
1176 if (lhsLV.isBitField())
1177 cgf.emitStoreThroughBitfieldLValue(RValue::get(result), lhsLV);
1178 else
1179 cgf.emitStoreThroughLValue(RValue::get(result), lhsLV);
1180
1181 if (cgf.getLangOpts().OpenMP)
1182 cgf.cgm.errorNYI(e->getSourceRange(), "openmp");
1183
1184 return lhsLV;
1185}
1186
1187mlir::Value ScalarExprEmitter::emitComplexToScalarConversion(mlir::Location lov,
1188 mlir::Value value,
1189 CastKind kind,
1190 QualType destTy) {
1191 cir::CastKind castOpKind;
1192 switch (kind) {
1193 case CK_FloatingComplexToReal:
1194 castOpKind = cir::CastKind::float_complex_to_real;
1195 break;
1196 case CK_IntegralComplexToReal:
1197 castOpKind = cir::CastKind::int_complex_to_real;
1198 break;
1199 case CK_FloatingComplexToBoolean:
1200 castOpKind = cir::CastKind::float_complex_to_bool;
1201 break;
1202 case CK_IntegralComplexToBoolean:
1203 castOpKind = cir::CastKind::int_complex_to_bool;
1204 break;
1205 default:
1206 llvm_unreachable("invalid complex-to-scalar cast kind");
1207 }
1208
1209 return builder.createCast(lov, castOpKind, value, cgf.convertType(destTy));
1210}
1211
1212mlir::Value ScalarExprEmitter::emitPromoted(const Expr *e,
1213 QualType promotionType) {
1214 e = e->IgnoreParens();
1215 if (const auto *bo = dyn_cast<BinaryOperator>(e)) {
1216 switch (bo->getOpcode()) {
1217#define HANDLE_BINOP(OP) \
1218 case BO_##OP: \
1219 return emit##OP(emitBinOps(bo, promotionType));
1220 HANDLE_BINOP(Add)
1221 HANDLE_BINOP(Sub)
1222 HANDLE_BINOP(Mul)
1223 HANDLE_BINOP(Div)
1224#undef HANDLE_BINOP
1225 default:
1226 break;
1227 }
1228 } else if (isa<UnaryOperator>(e)) {
1229 cgf.cgm.errorNYI(e->getSourceRange(), "unary operators");
1230 return {};
1231 }
1232 mlir::Value result = Visit(const_cast<Expr *>(e));
1233 if (result) {
1234 if (!promotionType.isNull())
1235 return emitPromotedValue(result, promotionType);
1236 return emitUnPromotedValue(result, e->getType());
1237 }
1238 return result;
1239}
1240
1241mlir::Value ScalarExprEmitter::emitCompoundAssign(
1242 const CompoundAssignOperator *e,
1243 mlir::Value (ScalarExprEmitter::*func)(const BinOpInfo &)) {
1244
1245 bool ignore = std::exchange(ignoreResultAssign, false);
1246 mlir::Value rhs;
1247 LValue lhs = emitCompoundAssignLValue(e, func, rhs);
1248
1249 // If the result is clearly ignored, return now.
1250 if (ignore)
1251 return {};
1252
1253 // The result of an assignment in C is the assigned r-value.
1254 if (!cgf.getLangOpts().CPlusPlus)
1255 return rhs;
1256
1257 // If the lvalue is non-volatile, return the computed value of the assignment.
1258 if (!lhs.isVolatile())
1259 return rhs;
1260
1261 // Otherwise, reload the value.
1262 return emitLoadOfLValue(lhs, e->getExprLoc());
1263}
1264
1265mlir::Value ScalarExprEmitter::VisitExprWithCleanups(ExprWithCleanups *e) {
1266 mlir::Location scopeLoc = cgf.getLoc(e->getSourceRange());
1267 mlir::OpBuilder &builder = cgf.builder;
1268
1269 auto scope = cir::ScopeOp::create(
1270 builder, scopeLoc,
1271 /*scopeBuilder=*/
1272 [&](mlir::OpBuilder &b, mlir::Type &yieldTy, mlir::Location loc) {
1273 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1274 builder.getInsertionBlock()};
1275 mlir::Value scopeYieldVal = Visit(e->getSubExpr());
1276 if (scopeYieldVal) {
1277 // Defend against dominance problems caused by jumps out of expression
1278 // evaluation through the shared cleanup block.
1279 lexScope.forceCleanup();
1280 cir::YieldOp::create(builder, loc, scopeYieldVal);
1281 yieldTy = scopeYieldVal.getType();
1282 }
1283 });
1284
1285 return scope.getNumResults() > 0 ? scope->getResult(0) : nullptr;
1286}
1287
1288} // namespace
1289
1290LValue
1292 ScalarExprEmitter emitter(*this, builder);
1293 mlir::Value result;
1294 switch (e->getOpcode()) {
1295#define COMPOUND_OP(Op) \
1296 case BO_##Op##Assign: \
1297 return emitter.emitCompoundAssignLValue(e, &ScalarExprEmitter::emit##Op, \
1298 result)
1299 COMPOUND_OP(Mul);
1300 COMPOUND_OP(Div);
1301 COMPOUND_OP(Rem);
1302 COMPOUND_OP(Add);
1303 COMPOUND_OP(Sub);
1304 COMPOUND_OP(Shl);
1305 COMPOUND_OP(Shr);
1307 COMPOUND_OP(Xor);
1308 COMPOUND_OP(Or);
1309#undef COMPOUND_OP
1310
1311 case BO_PtrMemD:
1312 case BO_PtrMemI:
1313 case BO_Mul:
1314 case BO_Div:
1315 case BO_Rem:
1316 case BO_Add:
1317 case BO_Sub:
1318 case BO_Shl:
1319 case BO_Shr:
1320 case BO_LT:
1321 case BO_GT:
1322 case BO_LE:
1323 case BO_GE:
1324 case BO_EQ:
1325 case BO_NE:
1326 case BO_Cmp:
1327 case BO_And:
1328 case BO_Xor:
1329 case BO_Or:
1330 case BO_LAnd:
1331 case BO_LOr:
1332 case BO_Assign:
1333 case BO_Comma:
1334 llvm_unreachable("Not valid compound assignment operators");
1335 }
1336 llvm_unreachable("Unhandled compound assignment operator");
1337}
1338
1339/// Emit the computation of the specified expression of scalar type.
1341 assert(e && hasScalarEvaluationKind(e->getType()) &&
1342 "Invalid scalar expression to emit");
1343
1344 return ScalarExprEmitter(*this, builder).Visit(const_cast<Expr *>(e));
1345}
1346
1348 QualType promotionType) {
1349 if (!promotionType.isNull())
1350 return ScalarExprEmitter(*this, builder).emitPromoted(e, promotionType);
1351 return ScalarExprEmitter(*this, builder).Visit(const_cast<Expr *>(e));
1352}
1353
1354[[maybe_unused]] static bool mustVisitNullValue(const Expr *e) {
1355 // If a null pointer expression's type is the C++0x nullptr_t and
1356 // the expression is not a simple literal, it must be evaluated
1357 // for its potential side effects.
1358 if (isa<IntegerLiteral>(e) || isa<CXXNullPtrLiteralExpr>(e))
1359 return false;
1360 return e->getType()->isNullPtrType();
1361}
1362
1363/// If \p e is a widened promoted integer, get its base (unpromoted) type.
1364static std::optional<QualType>
1365getUnwidenedIntegerType(const ASTContext &astContext, const Expr *e) {
1366 const Expr *base = e->IgnoreImpCasts();
1367 if (e == base)
1368 return std::nullopt;
1369
1370 QualType baseTy = base->getType();
1371 if (!astContext.isPromotableIntegerType(baseTy) ||
1372 astContext.getTypeSize(baseTy) >= astContext.getTypeSize(e->getType()))
1373 return std::nullopt;
1374
1375 return baseTy;
1376}
1377
1378/// Check if \p e is a widened promoted integer.
1379[[maybe_unused]] static bool isWidenedIntegerOp(const ASTContext &astContext,
1380 const Expr *e) {
1381 return getUnwidenedIntegerType(astContext, e).has_value();
1382}
1383
1384/// Check if we can skip the overflow check for \p Op.
1385[[maybe_unused]] static bool canElideOverflowCheck(const ASTContext &astContext,
1386 const BinOpInfo &op) {
1387 assert((isa<UnaryOperator>(op.e) || isa<BinaryOperator>(op.e)) &&
1388 "Expected a unary or binary operator");
1389
1390 // If the binop has constant inputs and we can prove there is no overflow,
1391 // we can elide the overflow check.
1392 if (!op.mayHaveIntegerOverflow())
1393 return true;
1394
1395 // If a unary op has a widened operand, the op cannot overflow.
1396 if (const auto *uo = dyn_cast<UnaryOperator>(op.e))
1397 return !uo->canOverflow();
1398
1399 // We usually don't need overflow checks for binops with widened operands.
1400 // Multiplication with promoted unsigned operands is a special case.
1401 const auto *bo = cast<BinaryOperator>(op.e);
1402 std::optional<QualType> optionalLHSTy =
1403 getUnwidenedIntegerType(astContext, bo->getLHS());
1404 if (!optionalLHSTy)
1405 return false;
1406
1407 std::optional<QualType> optionalRHSTy =
1408 getUnwidenedIntegerType(astContext, bo->getRHS());
1409 if (!optionalRHSTy)
1410 return false;
1411
1412 QualType lhsTy = *optionalLHSTy;
1413 QualType rhsTy = *optionalRHSTy;
1414
1415 // This is the simple case: binops without unsigned multiplication, and with
1416 // widened operands. No overflow check is needed here.
1417 if ((op.opcode != BO_Mul && op.opcode != BO_MulAssign) ||
1418 !lhsTy->isUnsignedIntegerType() || !rhsTy->isUnsignedIntegerType())
1419 return true;
1420
1421 // For unsigned multiplication the overflow check can be elided if either one
1422 // of the unpromoted types are less than half the size of the promoted type.
1423 unsigned promotedSize = astContext.getTypeSize(op.e->getType());
1424 return (2 * astContext.getTypeSize(lhsTy)) < promotedSize ||
1425 (2 * astContext.getTypeSize(rhsTy)) < promotedSize;
1426}
1427
1428/// Emit pointer + index arithmetic.
1430 const BinOpInfo &op,
1431 bool isSubtraction) {
1432 // Must have binary (not unary) expr here. Unary pointer
1433 // increment/decrement doesn't use this path.
1434 const BinaryOperator *expr = cast<BinaryOperator>(op.e);
1435
1436 mlir::Value pointer = op.lhs;
1437 Expr *pointerOperand = expr->getLHS();
1438 mlir::Value index = op.rhs;
1439 Expr *indexOperand = expr->getRHS();
1440
1441 // In the case of subtraction, the FE has ensured that the LHS is always the
1442 // pointer. However, addition can have the pointer on either side. We will
1443 // always have a pointer operand and an integer operand, so if the LHS wasn't
1444 // a pointer, we need to swap our values.
1445 if (!isSubtraction && !mlir::isa<cir::PointerType>(pointer.getType())) {
1446 std::swap(pointer, index);
1447 std::swap(pointerOperand, indexOperand);
1448 }
1449 assert(mlir::isa<cir::PointerType>(pointer.getType()) &&
1450 "Need a pointer operand");
1451 assert(mlir::isa<cir::IntType>(index.getType()) && "Need an integer operand");
1452
1453 // Some versions of glibc and gcc use idioms (particularly in their malloc
1454 // routines) that add a pointer-sized integer (known to be a pointer value)
1455 // to a null pointer in order to cast the value back to an integer or as
1456 // part of a pointer alignment algorithm. This is undefined behavior, but
1457 // we'd like to be able to compile programs that use it.
1458 //
1459 // Normally, we'd generate a GEP with a null-pointer base here in response
1460 // to that code, but it's also UB to dereference a pointer created that
1461 // way. Instead (as an acknowledged hack to tolerate the idiom) we will
1462 // generate a direct cast of the integer value to a pointer.
1463 //
1464 // The idiom (p = nullptr + N) is not met if any of the following are true:
1465 //
1466 // The operation is subtraction.
1467 // The index is not pointer-sized.
1468 // The pointer type is not byte-sized.
1469 //
1471 cgf.getContext(), op.opcode, expr->getLHS(), expr->getRHS()))
1472 return cgf.getBuilder().createIntToPtr(index, pointer.getType());
1473
1474 // Differently from LLVM codegen, ABI bits for index sizes is handled during
1475 // LLVM lowering.
1476
1477 // If this is subtraction, negate the index.
1478 if (isSubtraction)
1479 index = cgf.getBuilder().createNeg(index);
1480
1482
1483 const PointerType *pointerType =
1484 pointerOperand->getType()->getAs<PointerType>();
1485 if (!pointerType) {
1486 cgf.cgm.errorNYI("Objective-C:pointer arithmetic with non-pointer type");
1487 return nullptr;
1488 }
1489
1490 QualType elementType = pointerType->getPointeeType();
1491 if (cgf.getContext().getAsVariableArrayType(elementType)) {
1492 cgf.cgm.errorNYI("variable array type");
1493 return nullptr;
1494 }
1495
1496 if (elementType->isVoidType() || elementType->isFunctionType()) {
1497 cgf.cgm.errorNYI("void* or function pointer arithmetic");
1498 return nullptr;
1499 }
1500
1502 return cgf.getBuilder().create<cir::PtrStrideOp>(
1503 cgf.getLoc(op.e->getExprLoc()), pointer.getType(), pointer, index);
1504}
1505
1506mlir::Value ScalarExprEmitter::emitMul(const BinOpInfo &ops) {
1507 const mlir::Location loc = cgf.getLoc(ops.loc);
1508 if (ops.compType->isSignedIntegerOrEnumerationType()) {
1509 switch (cgf.getLangOpts().getSignedOverflowBehavior()) {
1511 if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))
1512 return builder.createMul(loc, ops.lhs, ops.rhs);
1513 [[fallthrough]];
1515 if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))
1516 return builder.createNSWMul(loc, ops.lhs, ops.rhs);
1517 [[fallthrough]];
1519 if (canElideOverflowCheck(cgf.getContext(), ops))
1520 return builder.createNSWMul(loc, ops.lhs, ops.rhs);
1521 cgf.cgm.errorNYI("sanitizers");
1522 }
1523 }
1524 if (ops.fullType->isConstantMatrixType()) {
1526 cgf.cgm.errorNYI("matrix types");
1527 return nullptr;
1528 }
1529 if (ops.compType->isUnsignedIntegerType() &&
1530 cgf.sanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
1531 !canElideOverflowCheck(cgf.getContext(), ops))
1532 cgf.cgm.errorNYI("unsigned int overflow sanitizer");
1533
1534 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
1536 return builder.createFMul(loc, ops.lhs, ops.rhs);
1537 }
1538
1539 if (ops.isFixedPointOp()) {
1541 cgf.cgm.errorNYI("fixed point");
1542 return nullptr;
1543 }
1544
1545 return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),
1546 cgf.convertType(ops.fullType),
1547 cir::BinOpKind::Mul, ops.lhs, ops.rhs);
1548}
1549mlir::Value ScalarExprEmitter::emitDiv(const BinOpInfo &ops) {
1550 return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),
1551 cgf.convertType(ops.fullType),
1552 cir::BinOpKind::Div, ops.lhs, ops.rhs);
1553}
1554mlir::Value ScalarExprEmitter::emitRem(const BinOpInfo &ops) {
1555 return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),
1556 cgf.convertType(ops.fullType),
1557 cir::BinOpKind::Rem, ops.lhs, ops.rhs);
1558}
1559
1560mlir::Value ScalarExprEmitter::emitAdd(const BinOpInfo &ops) {
1561 if (mlir::isa<cir::PointerType>(ops.lhs.getType()) ||
1562 mlir::isa<cir::PointerType>(ops.rhs.getType()))
1563 return emitPointerArithmetic(cgf, ops, /*isSubtraction=*/false);
1564
1565 const mlir::Location loc = cgf.getLoc(ops.loc);
1566 if (ops.compType->isSignedIntegerOrEnumerationType()) {
1567 switch (cgf.getLangOpts().getSignedOverflowBehavior()) {
1569 if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))
1570 return builder.createAdd(loc, ops.lhs, ops.rhs);
1571 [[fallthrough]];
1573 if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))
1574 return builder.createNSWAdd(loc, ops.lhs, ops.rhs);
1575 [[fallthrough]];
1577 if (canElideOverflowCheck(cgf.getContext(), ops))
1578 return builder.createNSWAdd(loc, ops.lhs, ops.rhs);
1579 cgf.cgm.errorNYI("sanitizers");
1580 }
1581 }
1582 if (ops.fullType->isConstantMatrixType()) {
1584 cgf.cgm.errorNYI("matrix types");
1585 return nullptr;
1586 }
1587
1588 if (ops.compType->isUnsignedIntegerType() &&
1589 cgf.sanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
1590 !canElideOverflowCheck(cgf.getContext(), ops))
1591 cgf.cgm.errorNYI("unsigned int overflow sanitizer");
1592
1593 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
1595 return builder.createFAdd(loc, ops.lhs, ops.rhs);
1596 }
1597
1598 if (ops.isFixedPointOp()) {
1600 cgf.cgm.errorNYI("fixed point");
1601 return {};
1602 }
1603
1604 return builder.create<cir::BinOp>(loc, cgf.convertType(ops.fullType),
1605 cir::BinOpKind::Add, ops.lhs, ops.rhs);
1606}
1607
1608mlir::Value ScalarExprEmitter::emitSub(const BinOpInfo &ops) {
1609 const mlir::Location loc = cgf.getLoc(ops.loc);
1610 // The LHS is always a pointer if either side is.
1611 if (!mlir::isa<cir::PointerType>(ops.lhs.getType())) {
1612 if (ops.compType->isSignedIntegerOrEnumerationType()) {
1613 switch (cgf.getLangOpts().getSignedOverflowBehavior()) {
1615 if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))
1616 return builder.createSub(loc, ops.lhs, ops.rhs);
1617 [[fallthrough]];
1618 }
1620 if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))
1621 return builder.createNSWSub(loc, ops.lhs, ops.rhs);
1622 [[fallthrough]];
1624 if (canElideOverflowCheck(cgf.getContext(), ops))
1625 return builder.createNSWSub(loc, ops.lhs, ops.rhs);
1626 cgf.cgm.errorNYI("sanitizers");
1627 }
1628 }
1629
1630 if (ops.fullType->isConstantMatrixType()) {
1632 cgf.cgm.errorNYI("matrix types");
1633 return nullptr;
1634 }
1635
1636 if (ops.compType->isUnsignedIntegerType() &&
1637 cgf.sanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
1638 !canElideOverflowCheck(cgf.getContext(), ops))
1639 cgf.cgm.errorNYI("unsigned int overflow sanitizer");
1640
1641 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
1643 return builder.createFSub(loc, ops.lhs, ops.rhs);
1644 }
1645
1646 if (ops.isFixedPointOp()) {
1648 cgf.cgm.errorNYI("fixed point");
1649 return {};
1650 }
1651
1652 return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),
1653 cgf.convertType(ops.fullType),
1654 cir::BinOpKind::Sub, ops.lhs, ops.rhs);
1655 }
1656
1657 // If the RHS is not a pointer, then we have normal pointer
1658 // arithmetic.
1659 if (!mlir::isa<cir::PointerType>(ops.rhs.getType()))
1660 return emitPointerArithmetic(cgf, ops, /*isSubtraction=*/true);
1661
1662 // Otherwise, this is a pointer subtraction
1663
1664 // Do the raw subtraction part.
1665 //
1666 // TODO(cir): note for LLVM lowering out of this; when expanding this into
1667 // LLVM we shall take VLA's, division by element size, etc.
1668 //
1669 // See more in `EmitSub` in CGExprScalar.cpp.
1671 cgf.cgm.errorNYI("ptrdiff");
1672 return {};
1673}
1674
1675mlir::Value ScalarExprEmitter::emitShl(const BinOpInfo &ops) {
1676 // TODO: This misses out on the sanitizer check below.
1677 if (ops.isFixedPointOp()) {
1679 cgf.cgm.errorNYI("fixed point");
1680 return {};
1681 }
1682
1683 // CIR accepts shift between different types, meaning nothing special
1684 // to be done here. OTOH, LLVM requires the LHS and RHS to be the same type:
1685 // promote or truncate the RHS to the same size as the LHS.
1686
1687 bool sanitizeSignedBase = cgf.sanOpts.has(SanitizerKind::ShiftBase) &&
1688 ops.compType->hasSignedIntegerRepresentation() &&
1690 !cgf.getLangOpts().CPlusPlus20;
1691 bool sanitizeUnsignedBase =
1692 cgf.sanOpts.has(SanitizerKind::UnsignedShiftBase) &&
1693 ops.compType->hasUnsignedIntegerRepresentation();
1694 bool sanitizeBase = sanitizeSignedBase || sanitizeUnsignedBase;
1695 bool sanitizeExponent = cgf.sanOpts.has(SanitizerKind::ShiftExponent);
1696
1697 // OpenCL 6.3j: shift values are effectively % word size of LHS.
1698 if (cgf.getLangOpts().OpenCL)
1699 cgf.cgm.errorNYI("opencl");
1700 else if ((sanitizeBase || sanitizeExponent) &&
1701 mlir::isa<cir::IntType>(ops.lhs.getType()))
1702 cgf.cgm.errorNYI("sanitizers");
1703
1704 return builder.createShiftLeft(cgf.getLoc(ops.loc), ops.lhs, ops.rhs);
1705}
1706
1707mlir::Value ScalarExprEmitter::emitShr(const BinOpInfo &ops) {
1708 // TODO: This misses out on the sanitizer check below.
1709 if (ops.isFixedPointOp()) {
1711 cgf.cgm.errorNYI("fixed point");
1712 return {};
1713 }
1714
1715 // CIR accepts shift between different types, meaning nothing special
1716 // to be done here. OTOH, LLVM requires the LHS and RHS to be the same type:
1717 // promote or truncate the RHS to the same size as the LHS.
1718
1719 // OpenCL 6.3j: shift values are effectively % word size of LHS.
1720 if (cgf.getLangOpts().OpenCL)
1721 cgf.cgm.errorNYI("opencl");
1722 else if (cgf.sanOpts.has(SanitizerKind::ShiftExponent) &&
1723 mlir::isa<cir::IntType>(ops.lhs.getType()))
1724 cgf.cgm.errorNYI("sanitizers");
1725
1726 // Note that we don't need to distinguish unsigned treatment at this
1727 // point since it will be handled later by LLVM lowering.
1728 return builder.createShiftRight(cgf.getLoc(ops.loc), ops.lhs, ops.rhs);
1729}
1730
1731mlir::Value ScalarExprEmitter::emitAnd(const BinOpInfo &ops) {
1732 return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),
1733 cgf.convertType(ops.fullType),
1734 cir::BinOpKind::And, ops.lhs, ops.rhs);
1735}
1736mlir::Value ScalarExprEmitter::emitXor(const BinOpInfo &ops) {
1737 return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),
1738 cgf.convertType(ops.fullType),
1739 cir::BinOpKind::Xor, ops.lhs, ops.rhs);
1740}
1741mlir::Value ScalarExprEmitter::emitOr(const BinOpInfo &ops) {
1742 return builder.create<cir::BinOp>(cgf.getLoc(ops.loc),
1743 cgf.convertType(ops.fullType),
1744 cir::BinOpKind::Or, ops.lhs, ops.rhs);
1745}
1746
1747// Emit code for an explicit or implicit cast. Implicit
1748// casts have to handle a more broad range of conversions than explicit
1749// casts, as they handle things like function to ptr-to-function decay
1750// etc.
1751mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
1752 Expr *subExpr = ce->getSubExpr();
1753 QualType destTy = ce->getType();
1754 CastKind kind = ce->getCastKind();
1755
1756 // These cases are generally not written to ignore the result of evaluating
1757 // their sub-expressions, so we clear this now.
1758 ignoreResultAssign = false;
1759
1760 switch (kind) {
1761 case clang::CK_Dependent:
1762 llvm_unreachable("dependent cast kind in CIR gen!");
1763 case clang::CK_BuiltinFnToFnPtr:
1764 llvm_unreachable("builtin functions are handled elsewhere");
1765
1766 case CK_CPointerToObjCPointerCast:
1767 case CK_BlockPointerToObjCPointerCast:
1768 case CK_AnyPointerToBlockPointerCast:
1769 case CK_BitCast: {
1770 mlir::Value src = Visit(const_cast<Expr *>(subExpr));
1771 mlir::Type dstTy = cgf.convertType(destTy);
1772
1774
1775 if (cgf.sanOpts.has(SanitizerKind::CFIUnrelatedCast))
1776 cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
1777 "sanitizer support");
1778
1779 if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)
1780 cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
1781 "strict vtable pointers");
1782
1783 // Update heapallocsite metadata when there is an explicit pointer cast.
1785
1786 // If Src is a fixed vector and Dst is a scalable vector, and both have the
1787 // same element type, use the llvm.vector.insert intrinsic to perform the
1788 // bitcast.
1790
1791 // If Src is a scalable vector and Dst is a fixed vector, and both have the
1792 // same element type, use the llvm.vector.extract intrinsic to perform the
1793 // bitcast.
1795
1796 // Perform VLAT <-> VLST bitcast through memory.
1797 // TODO: since the llvm.experimental.vector.{insert,extract} intrinsics
1798 // require the element types of the vectors to be the same, we
1799 // need to keep this around for bitcasts between VLAT <-> VLST where
1800 // the element types of the vectors are not the same, until we figure
1801 // out a better way of doing these casts.
1803
1804 return cgf.getBuilder().createBitcast(cgf.getLoc(subExpr->getSourceRange()),
1805 src, dstTy);
1806 }
1807
1808 case CK_AtomicToNonAtomic: {
1809 cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
1810 "CastExpr: ", ce->getCastKindName());
1811 mlir::Location loc = cgf.getLoc(subExpr->getSourceRange());
1812 return cgf.createDummyValue(loc, destTy);
1813 }
1814 case CK_NonAtomicToAtomic:
1815 case CK_UserDefinedConversion:
1816 return Visit(const_cast<Expr *>(subExpr));
1817 case CK_NoOp: {
1818 auto v = Visit(const_cast<Expr *>(subExpr));
1819 if (v) {
1820 // CK_NoOp can model a pointer qualification conversion, which can remove
1821 // an array bound and change the IR type.
1822 // FIXME: Once pointee types are removed from IR, remove this.
1823 mlir::Type t = cgf.convertType(destTy);
1824 if (t != v.getType())
1825 cgf.getCIRGenModule().errorNYI("pointer qualification conversion");
1826 }
1827 return v;
1828 }
1829
1830 case CK_ArrayToPointerDecay:
1831 return cgf.emitArrayToPointerDecay(subExpr).getPointer();
1832
1833 case CK_NullToPointer: {
1834 if (mustVisitNullValue(subExpr))
1835 cgf.emitIgnoredExpr(subExpr);
1836
1837 // Note that DestTy is used as the MLIR type instead of a custom
1838 // nullptr type.
1839 mlir::Type ty = cgf.convertType(destTy);
1840 return builder.getNullPtr(ty, cgf.getLoc(subExpr->getExprLoc()));
1841 }
1842
1843 case CK_LValueToRValue:
1844 assert(cgf.getContext().hasSameUnqualifiedType(subExpr->getType(), destTy));
1845 assert(subExpr->isGLValue() && "lvalue-to-rvalue applied to r-value!");
1846 return Visit(const_cast<Expr *>(subExpr));
1847
1848 case CK_IntegralCast: {
1849 ScalarConversionOpts opts;
1850 if (auto *ice = dyn_cast<ImplicitCastExpr>(ce)) {
1851 if (!ice->isPartOfExplicitCast())
1852 opts = ScalarConversionOpts(cgf.sanOpts);
1853 }
1854 return emitScalarConversion(Visit(subExpr), subExpr->getType(), destTy,
1855 ce->getExprLoc(), opts);
1856 }
1857
1858 case CK_FloatingComplexToReal:
1859 case CK_IntegralComplexToReal:
1860 case CK_FloatingComplexToBoolean:
1861 case CK_IntegralComplexToBoolean: {
1862 mlir::Value value = cgf.emitComplexExpr(subExpr);
1863 return emitComplexToScalarConversion(cgf.getLoc(ce->getExprLoc()), value,
1864 kind, destTy);
1865 }
1866
1867 case CK_FloatingRealToComplex:
1868 case CK_FloatingComplexCast:
1869 case CK_IntegralRealToComplex:
1870 case CK_IntegralComplexCast:
1871 case CK_IntegralComplexToFloatingComplex:
1872 case CK_FloatingComplexToIntegralComplex:
1873 llvm_unreachable("scalar cast to non-scalar value");
1874
1875 case CK_PointerToIntegral: {
1876 assert(!destTy->isBooleanType() && "bool should use PointerToBool");
1877 if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)
1878 cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
1879 "strict vtable pointers");
1880 return builder.createPtrToInt(Visit(subExpr), cgf.convertType(destTy));
1881 }
1882 case CK_ToVoid:
1883 cgf.emitIgnoredExpr(subExpr);
1884 return {};
1885
1886 case CK_IntegralToFloating:
1887 case CK_FloatingToIntegral:
1888 case CK_FloatingCast:
1889 case CK_FixedPointToFloating:
1890 case CK_FloatingToFixedPoint: {
1891 if (kind == CK_FixedPointToFloating || kind == CK_FloatingToFixedPoint) {
1892 cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
1893 "fixed point casts");
1894 return {};
1895 }
1897 return emitScalarConversion(Visit(subExpr), subExpr->getType(), destTy,
1898 ce->getExprLoc());
1899 }
1900
1901 case CK_IntegralToBoolean:
1902 return emitIntToBoolConversion(Visit(subExpr),
1903 cgf.getLoc(ce->getSourceRange()));
1904
1905 case CK_PointerToBoolean:
1906 return emitPointerToBoolConversion(Visit(subExpr), subExpr->getType());
1907 case CK_FloatingToBoolean:
1908 return emitFloatToBoolConversion(Visit(subExpr),
1909 cgf.getLoc(subExpr->getExprLoc()));
1910 case CK_MemberPointerToBoolean: {
1911 mlir::Value memPtr = Visit(subExpr);
1912 return builder.createCast(cgf.getLoc(ce->getSourceRange()),
1913 cir::CastKind::member_ptr_to_bool, memPtr,
1914 cgf.convertType(destTy));
1915 }
1916
1917 case CK_VectorSplat: {
1918 // Create a vector object and fill all elements with the same scalar value.
1919 assert(destTy->isVectorType() && "CK_VectorSplat to non-vector type");
1920 return builder.create<cir::VecSplatOp>(
1921 cgf.getLoc(subExpr->getSourceRange()), cgf.convertType(destTy),
1922 Visit(subExpr));
1923 }
1924 case CK_FunctionToPointerDecay:
1925 return cgf.emitLValue(subExpr).getPointer();
1926
1927 default:
1928 cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
1929 "CastExpr: ", ce->getCastKindName());
1930 }
1931 return {};
1932}
1933
1934mlir::Value ScalarExprEmitter::VisitCallExpr(const CallExpr *e) {
1936 return emitLoadOfLValue(e);
1937
1938 auto v = cgf.emitCallExpr(e).getValue();
1940 return v;
1941}
1942
1943mlir::Value ScalarExprEmitter::VisitMemberExpr(MemberExpr *e) {
1944 // TODO(cir): The classic codegen calls tryEmitAsConstant() here. Folding
1945 // constants sound like work for MLIR optimizers, but we'll keep an assertion
1946 // for now.
1948 Expr::EvalResult result;
1949 if (e->EvaluateAsInt(result, cgf.getContext(), Expr::SE_AllowSideEffects)) {
1950 cgf.cgm.errorNYI(e->getSourceRange(), "Constant interger member expr");
1951 // Fall through to emit this as a non-constant access.
1952 }
1953 return emitLoadOfLValue(e);
1954}
1955
1956mlir::Value ScalarExprEmitter::VisitInitListExpr(InitListExpr *e) {
1957 const unsigned numInitElements = e->getNumInits();
1958
1959 if (e->hadArrayRangeDesignator()) {
1960 cgf.cgm.errorNYI(e->getSourceRange(), "ArrayRangeDesignator");
1961 return {};
1962 }
1963
1964 if (e->getType()->isVectorType()) {
1965 const auto vectorType =
1966 mlir::cast<cir::VectorType>(cgf.convertType(e->getType()));
1967
1969 for (Expr *init : e->inits()) {
1970 elements.push_back(Visit(init));
1971 }
1972
1973 // Zero-initialize any remaining values.
1974 if (numInitElements < vectorType.getSize()) {
1975 const mlir::Value zeroValue = cgf.getBuilder().getNullValue(
1976 vectorType.getElementType(), cgf.getLoc(e->getSourceRange()));
1977 std::fill_n(std::back_inserter(elements),
1978 vectorType.getSize() - numInitElements, zeroValue);
1979 }
1980
1981 return cgf.getBuilder().create<cir::VecCreateOp>(
1982 cgf.getLoc(e->getSourceRange()), vectorType, elements);
1983 }
1984
1985 // C++11 value-initialization for the scalar.
1986 if (numInitElements == 0)
1987 return emitNullValue(e->getType(), cgf.getLoc(e->getExprLoc()));
1988
1989 return Visit(e->getInit(0));
1990}
1991
1992mlir::Value CIRGenFunction::emitScalarConversion(mlir::Value src,
1993 QualType srcTy, QualType dstTy,
1994 SourceLocation loc) {
1997 "Invalid scalar expression to emit");
1998 return ScalarExprEmitter(*this, builder)
1999 .emitScalarConversion(src, srcTy, dstTy, loc);
2000}
2001
2003 QualType srcTy,
2004 QualType dstTy,
2005 SourceLocation loc) {
2006 assert(srcTy->isAnyComplexType() && hasScalarEvaluationKind(dstTy) &&
2007 "Invalid complex -> scalar conversion");
2008
2009 QualType complexElemTy = srcTy->castAs<ComplexType>()->getElementType();
2010 if (dstTy->isBooleanType()) {
2011 auto kind = complexElemTy->isFloatingType()
2012 ? cir::CastKind::float_complex_to_bool
2013 : cir::CastKind::int_complex_to_bool;
2014 return builder.createCast(getLoc(loc), kind, src, convertType(dstTy));
2015 }
2016
2017 auto kind = complexElemTy->isFloatingType()
2018 ? cir::CastKind::float_complex_to_real
2019 : cir::CastKind::int_complex_to_real;
2020 mlir::Value real =
2021 builder.createCast(getLoc(loc), kind, src, convertType(complexElemTy));
2022 return emitScalarConversion(real, complexElemTy, dstTy, loc);
2023}
2024
2025mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *e) {
2026 // Perform vector logical not on comparison with zero vector.
2027 if (e->getType()->isVectorType() &&
2028 e->getType()->castAs<VectorType>()->getVectorKind() ==
2031 cgf.cgm.errorNYI(e->getSourceRange(), "vector logical not");
2032 return {};
2033 }
2034
2035 // Compare operand to zero.
2036 mlir::Value boolVal = cgf.evaluateExprAsBool(e->getSubExpr());
2037
2038 // Invert value.
2039 boolVal = builder.createNot(boolVal);
2040
2041 // ZExt result to the expr type.
2042 return maybePromoteBoolResult(boolVal, cgf.convertType(e->getType()));
2043}
2044
2045mlir::Value ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *e) {
2046 // TODO(cir): handle scalar promotion.
2047 Expr *op = e->getSubExpr();
2048 if (op->getType()->isAnyComplexType()) {
2049 // If it's an l-value, load through the appropriate subobject l-value.
2050 // Note that we have to ask `e` because `op` might be an l-value that
2051 // this won't work for, e.g. an Obj-C property.
2052 if (e->isGLValue()) {
2053 mlir::Location loc = cgf.getLoc(e->getExprLoc());
2054 mlir::Value complex = cgf.emitComplexExpr(op);
2055 return cgf.builder.createComplexReal(loc, complex);
2056 }
2057
2058 // Otherwise, calculate and project.
2059 cgf.cgm.errorNYI(e->getSourceRange(),
2060 "VisitUnaryReal calculate and project");
2061 }
2062
2063 return Visit(op);
2064}
2065
2066mlir::Value ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *e) {
2067 // TODO(cir): handle scalar promotion.
2068 Expr *op = e->getSubExpr();
2069 if (op->getType()->isAnyComplexType()) {
2070 // If it's an l-value, load through the appropriate subobject l-value.
2071 // Note that we have to ask `e` because `op` might be an l-value that
2072 // this won't work for, e.g. an Obj-C property.
2073 if (e->isGLValue()) {
2074 mlir::Location loc = cgf.getLoc(e->getExprLoc());
2075 mlir::Value complex = cgf.emitComplexExpr(op);
2076 return cgf.builder.createComplexImag(loc, complex);
2077 }
2078
2079 // Otherwise, calculate and project.
2080 cgf.cgm.errorNYI(e->getSourceRange(),
2081 "VisitUnaryImag calculate and project");
2082 }
2083
2084 return Visit(op);
2085}
2086
2087/// Return the size or alignment of the type of argument of the sizeof
2088/// expression as an integer.
2089mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
2090 const UnaryExprOrTypeTraitExpr *e) {
2091 const QualType typeToSize = e->getTypeOfArgument();
2092 const mlir::Location loc = cgf.getLoc(e->getSourceRange());
2093 if (auto kind = e->getKind();
2094 kind == UETT_SizeOf || kind == UETT_DataSizeOf) {
2095 if (cgf.getContext().getAsVariableArrayType(typeToSize)) {
2097 "sizeof operator for VariableArrayType",
2098 e->getStmtClassName());
2099 return builder.getConstant(
2100 loc, cir::IntAttr::get(cgf.cgm.UInt64Ty,
2101 llvm::APSInt(llvm::APInt(64, 1), true)));
2102 }
2103 } else if (e->getKind() == UETT_OpenMPRequiredSimdAlign) {
2105 e->getSourceRange(), "sizeof operator for OpenMpRequiredSimdAlign",
2106 e->getStmtClassName());
2107 return builder.getConstant(
2108 loc, cir::IntAttr::get(cgf.cgm.UInt64Ty,
2109 llvm::APSInt(llvm::APInt(64, 1), true)));
2110 }
2111
2112 return builder.getConstant(
2113 loc, cir::IntAttr::get(cgf.cgm.UInt64Ty,
2115}
2116
2117/// Return true if the specified expression is cheap enough and side-effect-free
2118/// enough to evaluate unconditionally instead of conditionally. This is used
2119/// to convert control flow into selects in some cases.
2120/// TODO(cir): can be shared with LLVM codegen.
2122 CIRGenFunction &cgf) {
2123 // Anything that is an integer or floating point constant is fine.
2124 return e->IgnoreParens()->isEvaluatable(cgf.getContext());
2125
2126 // Even non-volatile automatic variables can't be evaluated unconditionally.
2127 // Referencing a thread_local may cause non-trivial initialization work to
2128 // occur. If we're inside a lambda and one of the variables is from the scope
2129 // outside the lambda, that function may have returned already. Reading its
2130 // locals is a bad idea. Also, these reads may introduce races there didn't
2131 // exist in the source-level program.
2132}
2133
2134mlir::Value ScalarExprEmitter::VisitAbstractConditionalOperator(
2135 const AbstractConditionalOperator *e) {
2136 CIRGenBuilderTy &builder = cgf.getBuilder();
2137 mlir::Location loc = cgf.getLoc(e->getSourceRange());
2138 ignoreResultAssign = false;
2139
2140 // Bind the common expression if necessary.
2141 CIRGenFunction::OpaqueValueMapping binding(cgf, e);
2142
2143 Expr *condExpr = e->getCond();
2144 Expr *lhsExpr = e->getTrueExpr();
2145 Expr *rhsExpr = e->getFalseExpr();
2146
2147 // If the condition constant folds and can be elided, try to avoid emitting
2148 // the condition and the dead arm.
2149 bool condExprBool;
2150 if (cgf.constantFoldsToBool(condExpr, condExprBool)) {
2151 Expr *live = lhsExpr, *dead = rhsExpr;
2152 if (!condExprBool)
2153 std::swap(live, dead);
2154
2155 // If the dead side doesn't have labels we need, just emit the Live part.
2156 if (!cgf.containsLabel(dead)) {
2157 if (condExprBool)
2159 mlir::Value result = Visit(live);
2160
2161 // If the live part is a throw expression, it acts like it has a void
2162 // type, so evaluating it returns a null Value. However, a conditional
2163 // with non-void type must return a non-null Value.
2164 if (!result && !e->getType()->isVoidType()) {
2165 cgf.cgm.errorNYI(e->getSourceRange(),
2166 "throw expression in conditional operator");
2167 result = {};
2168 }
2169
2170 return result;
2171 }
2172 }
2173
2174 QualType condType = condExpr->getType();
2175
2176 // OpenCL: If the condition is a vector, we can treat this condition like
2177 // the select function.
2178 if ((cgf.getLangOpts().OpenCL && condType->isVectorType()) ||
2179 condType->isExtVectorType()) {
2181 cgf.cgm.errorNYI(e->getSourceRange(), "vector ternary op");
2182 }
2183
2184 if (condType->isVectorType() || condType->isSveVLSBuiltinType()) {
2185 if (!condType->isVectorType()) {
2187 cgf.cgm.errorNYI(loc, "TernaryOp for SVE vector");
2188 return {};
2189 }
2190
2191 mlir::Value condValue = Visit(condExpr);
2192 mlir::Value lhsValue = Visit(lhsExpr);
2193 mlir::Value rhsValue = Visit(rhsExpr);
2194 return builder.create<cir::VecTernaryOp>(loc, condValue, lhsValue,
2195 rhsValue);
2196 }
2197
2198 // If this is a really simple expression (like x ? 4 : 5), emit this as a
2199 // select instead of as control flow. We can only do this if it is cheap
2200 // and safe to evaluate the LHS and RHS unconditionally.
2201 if (isCheapEnoughToEvaluateUnconditionally(lhsExpr, cgf) &&
2203 bool lhsIsVoid = false;
2204 mlir::Value condV = cgf.evaluateExprAsBool(condExpr);
2206
2207 mlir::Value lhs = Visit(lhsExpr);
2208 if (!lhs) {
2209 lhs = builder.getNullValue(cgf.VoidTy, loc);
2210 lhsIsVoid = true;
2211 }
2212
2213 mlir::Value rhs = Visit(rhsExpr);
2214 if (lhsIsVoid) {
2215 assert(!rhs && "lhs and rhs types must match");
2216 rhs = builder.getNullValue(cgf.VoidTy, loc);
2217 }
2218
2219 return builder.createSelect(loc, condV, lhs, rhs);
2220 }
2221
2222 mlir::Value condV = cgf.emitOpOnBoolExpr(loc, condExpr);
2225 mlir::Type yieldTy{};
2226
2227 auto emitBranch = [&](mlir::OpBuilder &b, mlir::Location loc, Expr *expr) {
2228 CIRGenFunction::LexicalScope lexScope{cgf, loc, b.getInsertionBlock()};
2230
2232 eval.beginEvaluation();
2233 mlir::Value branch = Visit(expr);
2234 eval.endEvaluation();
2235
2236 if (branch) {
2237 yieldTy = branch.getType();
2238 b.create<cir::YieldOp>(loc, branch);
2239 } else {
2240 // If LHS or RHS is a throw or void expression we need to patch
2241 // arms as to properly match yield types.
2242 insertPoints.push_back(b.saveInsertionPoint());
2243 }
2244 };
2245
2246 mlir::Value result = builder
2247 .create<cir::TernaryOp>(
2248 loc, condV,
2249 /*trueBuilder=*/
2250 [&](mlir::OpBuilder &b, mlir::Location loc) {
2251 emitBranch(b, loc, lhsExpr);
2252 },
2253 /*falseBuilder=*/
2254 [&](mlir::OpBuilder &b, mlir::Location loc) {
2255 emitBranch(b, loc, rhsExpr);
2256 })
2257 .getResult();
2258
2259 if (!insertPoints.empty()) {
2260 // If both arms are void, so be it.
2261 if (!yieldTy)
2262 yieldTy = cgf.VoidTy;
2263
2264 // Insert required yields.
2265 for (mlir::OpBuilder::InsertPoint &toInsert : insertPoints) {
2266 mlir::OpBuilder::InsertionGuard guard(builder);
2267 builder.restoreInsertionPoint(toInsert);
2268
2269 // Block does not return: build empty yield.
2270 if (mlir::isa<cir::VoidType>(yieldTy)) {
2271 builder.create<cir::YieldOp>(loc);
2272 } else { // Block returns: set null yield value.
2273 mlir::Value op0 = builder.getNullValue(yieldTy, loc);
2274 builder.create<cir::YieldOp>(loc, op0);
2275 }
2276 }
2277 }
2278
2279 return result;
2280}
2281
2283 LValue lv,
2284 cir::UnaryOpKind kind,
2285 bool isPre) {
2286 return ScalarExprEmitter(*this, builder)
2287 .emitScalarPrePostIncDec(e, lv, kind, isPre);
2288}
ASTImporterLookupTable & LT
static bool mustVisitNullValue(const Expr *e)
#define COMPOUND_OP(Op)
#define HANDLEBINOP(OP)
static bool isWidenedIntegerOp(const ASTContext &astContext, const Expr *e)
Check if e is a widened promoted integer.
static mlir::Value emitPointerArithmetic(CIRGenFunction &cgf, const BinOpInfo &op, bool isSubtraction)
Emit pointer + index arithmetic.
static bool isCheapEnoughToEvaluateUnconditionally(const Expr *e, CIRGenFunction &cgf)
Return true if the specified expression is cheap enough and side-effect-free enough to evaluate uncon...
static bool canElideOverflowCheck(const ASTContext &astContext, const BinOpInfo &op)
Check if we can skip the overflow check for Op.
static std::optional< QualType > getUnwidenedIntegerType(const ASTContext &astContext, const Expr *e)
If e is a widened promoted integer, get its base (unpromoted) type.
#define VISITCOMP(CODE)
#define HANDLE_BINOP(OP)
__device__ __2f16 b
__device__ __2f16 float __ockl_bool s
cir::ConstantOp getBool(bool state, mlir::Location loc)
cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc)
mlir::Value createBoolToInt(mlir::Value src, mlir::Type newTy)
mlir::Value createCast(mlir::Location loc, cir::CastKind kind, mlir::Value src, mlir::Type newTy)
cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base, mlir::Value stride)
mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy)
mlir::Value createPtrToInt(mlir::Value src, mlir::Type newTy)
cir::ConstantOp getFalse(mlir::Location loc)
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand)
cir::ConstantOp getTrue(mlir::Location loc)
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 createSelect(mlir::Location loc, mlir::Value condition, mlir::Value trueValue, mlir::Value falseValue)
mlir::Value createPtrToBoolCast(mlir::Value v)
cir::BoolAttr getTrueAttr()
cir::BoolAttr getFalseAttr()
cir::BoolType getBoolTy()
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand)
llvm::APInt getValue() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
CanQualType FloatTy
Definition: ASTContext.h:1234
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2851
const LangOptions & getLangOpts() const
Definition: ASTContext.h:894
CanQualType BoolTy
Definition: ASTContext.h:1223
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
Definition: ASTContext.h:2898
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2625
QualType getPromotedIntegerType(QualType PromotableType) const
Return the type that PromotableType will promote to: C99 6.3.1.1p2, assuming that PromotableType is a...
const VariableArrayType * getAsVariableArrayType(QualType T) const
Definition: ASTContext.h:3059
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:859
bool isPromotableIntegerType(QualType T) const
More type predicates useful for type checking/promotion.
AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...
Definition: Expr.h:4289
Expr * getCond() const
getCond - Return the expression representing the condition for the ?: operator.
Definition: Expr.h:4467
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
Definition: Expr.h:4473
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Definition: Expr.h:4479
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition: Expr.h:2723
AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, __atomic_load,...
Definition: Expr.h:6816
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3974
Expr * getLHS() const
Definition: Expr.h:4024
SourceLocation getExprLoc() const
Definition: Expr.h:4015
Expr * getRHS() const
Definition: Expr.h:4026
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const
Get the FP features status of this operator.
Definition: Expr.h:4187
static bool isNullPointerArithmeticExtension(ASTContext &Ctx, Opcode Opc, const Expr *LHS, const Expr *RHS)
Return true if a binary operator using the specified opcode and operands would match the 'p = (i8*)nu...
Definition: Expr.cpp:2200
Opcode getOpcode() const
Definition: Expr.h:4019
mlir::Value getPointer() const
Definition: Address.h:81
cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc)
mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType)
cir::ConstantOp getSInt32(int32_t c, mlir::Location loc)
mlir::Value createNeg(mlir::Value value)
An object to manage conditionally-evaluated expressions.
An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
An RAII object to record that we're evaluating a statement expression.
static bool hasScalarEvaluationKind(clang::QualType type)
mlir::Value emitComplexToScalarConversion(mlir::Value src, QualType srcTy, QualType dstTy, SourceLocation loc)
Emit a conversion from the specified complex type to the specified destination type,...
mlir::Type convertType(clang::QualType t)
RValue emitLoadOfLValue(LValue lv, SourceLocation loc)
Given an expression that represents a value lvalue, this method emits the address of the lvalue,...
Definition: CIRGenExpr.cpp:566
const clang::LangOptions & getLangOpts() const
LValue emitScalarCompoundAssignWithComplex(const CompoundAssignOperator *e, mlir::Value &result)
mlir::Value emitComplexExpr(const Expr *e)
Emit the computation of the specified expression of complex type, returning the result.
mlir::Value loadCXXThis()
Load the value for 'this'.
RValue emitCallExpr(const clang::CallExpr *e, ReturnValueSlot returnValue=ReturnValueSlot())
LValue emitLValue(const clang::Expr *e)
Emit code to compute a designator that specifies the location of the expression.
mlir::Value evaluateExprAsBool(const clang::Expr *e)
Perform the usual unary conversions on the specified expression and compare the result against zero,...
Definition: CIRGenExpr.cpp:688
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
bool constantFoldsToBool(const clang::Expr *cond, bool &resultBool, bool allowLabels=false)
If the specified expression does not fold to a constant, or if it does but contains a label,...
mlir::Value emitOpOnBoolExpr(mlir::Location loc, const clang::Expr *cond)
TODO(cir): see EmitBranchOnBoolExpr for extra ideas).
mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv, cir::UnaryOpKind kind, bool isPre)
RValue emitAtomicExpr(AtomicExpr *e)
mlir::Value emitScalarConversion(mlir::Value src, clang::QualType srcType, clang::QualType dstType, clang::SourceLocation loc)
Emit a conversion from the specified type to the specified destination type, both of which are CIR sc...
clang::SanitizerSet sanOpts
Sanitizers enabled for this function.
mlir::Value createDummyValue(mlir::Location loc, clang::QualType qt)
LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e)
mlir::Value emitCXXNewExpr(const CXXNewExpr *e)
mlir::Value emitScalarExpr(const clang::Expr *e)
Emit the computation of the specified expression of scalar type.
mlir::Value emitPromotedScalarExpr(const Expr *e, QualType promotionType)
CIRGenBuilderTy & getBuilder()
CIRGenModule & getCIRGenModule()
mlir::Value emitLoadOfScalar(LValue lvalue, SourceLocation loc)
EmitLoadOfScalar - Load a scalar value from an address, taking care to appropriately convert from the...
Definition: CIRGenExpr.cpp:546
bool containsLabel(const clang::Stmt *s, bool ignoreCaseStmts=false)
Return true if the statement contains a label in it.
ConstantEmission tryEmitAsConstant(const DeclRefExpr *refExpr)
Try to emit a reference to the given value without producing it as an l-value.
void emitCXXThrowExpr(const CXXThrowExpr *e)
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
Address emitArrayToPointerDecay(const Expr *e, LValueBaseInfo *baseInfo=nullptr)
mlir::Value emitStoreThroughBitfieldLValue(RValue src, LValue dstresult)
Definition: CIRGenExpr.cpp:364
clang::ASTContext & getContext() const
mlir::Value emitScalarConstant(const ConstantEmission &constant, Expr *e)
mlir::LogicalResult emitCompoundStmt(const clang::CompoundStmt &s, Address *lastValue=nullptr, AggValueSlot slot=AggValueSlot::ignored())
Definition: CIRGenStmt.cpp:87
void emitNullabilityCheck(LValue lhs, mlir::Value rhs, clang::SourceLocation loc)
Given an assignment *lhs = rhs, emit a test that checks if rhs is nonnull, if 1LHS is marked _Nonnull...
Definition: CIRGenDecl.cpp:653
void emitStoreThroughLValue(RValue src, LValue dst, bool isInit=false)
Store the specified rvalue into the specified lvalue, where both are guaranteed to the have the same ...
Definition: CIRGenExpr.cpp:246
void emitIgnoredExpr(const clang::Expr *e)
Emit code to compute the specified expression, ignoring the result.
Address createMemTemp(QualType t, mlir::Location loc, const Twine &name="tmp", Address *alloca=nullptr, mlir::OpBuilder::InsertPoint ip={})
Create a temporary memory object of the given type, with appropriate alignmen and cast it to the defa...
mlir::Value emitVAArg(VAArgExpr *ve)
Generate code to get an argument from the passed in pointer and update it accordingly.
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
const clang::CodeGenOptions & getCodeGenOpts() const
Definition: CIRGenModule.h:104
mlir::Value emitNullConstant(QualType t, mlir::Location loc)
Return the result of value-initializing the given type, i.e.
mlir::Value getPointer() const
Definition: CIRGenValue.h:204
bool isBitField() const
Definition: CIRGenValue.h:192
bool isVolatile() const
Definition: CIRGenValue.h:194
static RValue get(mlir::Value v)
Definition: CIRGenValue.h:82
mlir::Value getValue() const
Return the value of this scalar value.
Definition: CIRGenValue.h:56
A boolean literal, per ([C++ lex.bool] Boolean literals).
Definition: ExprCXX.h:723
bool getValue() const
Definition: ExprCXX.h:740
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Definition: ExprCXX.h:2349
The null pointer literal (C++11 [lex.nullptr])
Definition: ExprCXX.h:768
An expression "T()" which creates an rvalue of a non-class type T.
Definition: ExprCXX.h:2198
Represents the this expression in C++.
Definition: ExprCXX.h:1155
A C++ throw-expression (C++ [except.throw]).
Definition: ExprCXX.h:1209
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2879
QualType getCallReturnType(const ASTContext &Ctx) const
getCallReturnType - Get the return type of the call expr.
Definition: Expr.cpp:1599
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3612
CastKind getCastKind() const
Definition: Expr.h:3656
static const char * getCastKindName(CastKind CK)
Definition: Expr.cpp:1946
Expr * getSubExpr()
Definition: Expr.h:3662
unsigned getValue() const
Definition: Expr.h:1631
Complex values, per C99 6.2.5p11.
Definition: TypeBase.h:3293
CompoundAssignOperator - For compound assignments (e.g.
Definition: Expr.h:4236
QualType getComputationLHSType() const
Definition: Expr.h:4270
QualType getComputationResultType() const
Definition: Expr.h:4273
CompoundLiteralExpr - [C99 6.5.2.5].
Definition: Expr.h:3541
ConvertVectorExpr - Clang builtin function __builtin_convertvector This AST node provides support for...
Definition: Expr.h:4655
Expr * getSrcExpr() const
getSrcExpr - Return the Expr to be converted.
Definition: Expr.h:4745
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1272
ExplicitCastExpr - An explicit cast written in the source code.
Definition: Expr.h:3864
Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...
Definition: ExprCXX.h:3655
This represents one expression.
Definition: Expr.h:112
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
bool isGLValue() const
Definition: Expr.h:287
@ SE_AllowSideEffects
Allow any unmodeled side effect.
Definition: Expr.h:674
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx, SmallVectorImpl< PartialDiagnosticAt > *Diag=nullptr) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3069
bool isEvaluatable(const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects) const
isEvaluatable - Call EvaluateAsRValue to see if this expression can be constant folded without side-e...
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3053
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:273
QualType getType() const
Definition: Expr.h:144
ExtVectorType - Extended vector type.
Definition: TypeBase.h:4283
llvm::APFloat getValue() const
Definition: Expr.h:1668
const Expr * getSubExpr() const
Definition: Expr.h:1064
Represents a C11 generic selection.
Definition: Expr.h:6114
Expr * getResultExpr()
Return the result expression of this controlling expression.
Definition: Expr.h:6398
Describes an C or C++ initializer list.
Definition: Expr.h:5235
unsigned getNumInits() const
Definition: Expr.h:5265
bool hadArrayRangeDesignator() const
Definition: Expr.h:5419
const Expr * getInit(unsigned Init) const
Definition: Expr.h:5289
ArrayRef< Expr * > inits()
Definition: Expr.h:5285
bool isSignedOverflowDefined() const
Definition: LangOptions.h:610
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3300
A pointer to member type per C++ 8.3.3 - Pointers to members.
Definition: TypeBase.h:3669
Represents a pointer to an Objective C object.
Definition: TypeBase.h:7961
Expr * getSelectedExpr() const
Definition: ExprCXX.h:4633
ParenExpr - This represents a parenthesized expression, e.g.
Definition: Expr.h:2184
const Expr * getSubExpr() const
Definition: Expr.h:2201
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: TypeBase.h:3346
A (possibly-)qualified type.
Definition: TypeBase.h:937
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: TypeBase.h:1004
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: TypeBase.h:8343
Qualifiers::ObjCLifetime getObjCLifetime() const
Returns lifetime attribute of this type.
Definition: TypeBase.h:1438
QualType getCanonicalType() const
Definition: TypeBase.h:8395
bool UseExcessPrecision(const ASTContext &Ctx)
Definition: Type.cpp:1612
bool isCanonical() const
Definition: TypeBase.h:8400
@ OCL_Strong
Assigning into this object requires the old value to be released and the new value to be retained.
Definition: TypeBase.h:361
@ OCL_ExplicitNone
This object can be modified without requiring retains or releases.
Definition: TypeBase.h:354
@ OCL_None
There is no lifetime qualification on this type.
Definition: TypeBase.h:350
@ OCL_Weak
Reading or writing from this object requires a barrier call.
Definition: TypeBase.h:364
@ OCL_Autoreleasing
Assigning into this object requires a lifetime extension.
Definition: TypeBase.h:367
ShuffleVectorExpr - clang-specific builtin-in function __builtin_shufflevector.
Definition: Expr.h:4579
unsigned getNumSubExprs() const
getNumSubExprs - Return the size of the SubExprs array.
Definition: Expr.h:4612
Expr * getExpr(unsigned Index)
getExpr - Return the Expr at the specified index.
Definition: Expr.h:4618
Encodes a location in the source.
A trivial tuple used to represent a source range.
SourceLocation getBegin() const
StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
Definition: Expr.h:4531
CompoundStmt * getSubStmt()
Definition: Expr.h:4548
RetTy Visit(PTR(Stmt) S, ParamTys... P)
Definition: StmtVisitor.h:45
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:186
Stmt - This represents one statement.
Definition: Stmt.h:85
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:334
const char * getStmtClassName() const
Definition: Stmt.cpp:87
Represents a reference to a non-type template parameter that has been substituted with a template arg...
Definition: ExprCXX.h:4658
virtual bool useFP16ConversionIntrinsics() const
Check whether llvm intrinsics such as llvm.convert.to.fp16 should be used to convert to and from __fp...
Definition: TargetInfo.h:1015
bool isVoidType() const
Definition: TypeBase.h:8936
bool isBooleanType() const
Definition: TypeBase.h:9066
bool isSignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...
Definition: Type.cpp:2229
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition: Type.cpp:2209
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition: TypeBase.h:8980
const T * castAs() const
Member-template castAs<specific type>.
Definition: TypeBase.h:9226
bool isReferenceType() const
Definition: TypeBase.h:8604
bool isSveVLSBuiltinType() const
Determines if this is a sizeless type supported by the 'arm_sve_vector_bits' type attribute,...
Definition: Type.cpp:2612
bool isExtVectorType() const
Definition: TypeBase.h:8723
bool isAnyComplexType() const
Definition: TypeBase.h:8715
bool isFixedPointType() const
Return true if this is a fixed point type according to ISO/IEC JTC1 SC22 WG14 N1169.
Definition: TypeBase.h:8992
bool isHalfType() const
Definition: TypeBase.h:8940
bool isMatrixType() const
Definition: TypeBase.h:8737
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition: TypeBase.h:2818
bool isFunctionType() const
Definition: TypeBase.h:8576
bool isVectorType() const
Definition: TypeBase.h:8719
bool isRealFloatingType() const
Floating point categories.
Definition: Type.cpp:2324
bool isFloatingType() const
Definition: Type.cpp:2308
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:2257
const T * getAs() const
Member-template getAs<specific type>'.
Definition: TypeBase.h:9159
bool isNullPtrType() const
Definition: TypeBase.h:8973
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
Definition: Expr.h:2627
QualType getTypeOfArgument() const
Gets the argument type, or the type of the argument expression, whichever is appropriate.
Definition: Expr.h:2696
UnaryExprOrTypeTrait getKind() const
Definition: Expr.h:2659
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition: Expr.h:2246
SourceLocation getExprLoc() const
Definition: Expr.h:2370
Expr * getSubExpr() const
Definition: Expr.h:2287
static bool isIncrementOp(Opcode Op)
Definition: Expr.h:2328
bool canOverflow() const
Returns true if the unary operator can cause an overflow.
Definition: Expr.h:2300
Represents a call to the builtin function __builtin_va_arg.
Definition: Expr.h:4893
Represents a GCC generic vector type.
Definition: TypeBase.h:4191
VectorKind getVectorKind() const
Definition: TypeBase.h:4211
QualType getElementType() const
Definition: TypeBase.h:4205
const AstTypeMatcher< PointerType > pointerType
Matches pointer types, but does not match Objective-C object pointer types.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::ArgumentAdaptingMatcherFunc< internal::HasMatcher > has
Matches AST nodes that have child AST nodes that match the provided matcher.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
unsigned kind
All of the diagnostics that can be emitted by the frontend.
Definition: DiagnosticIDs.h:76
The JSON file list parser is used to communicate input to InstallAPI.
BinaryOperatorKind
CastKind
CastKind - The kind of operation required for a conversion.
@ Generic
not a target-specific vector type
#define false
Definition: stdbool.h:26
static bool vectorType()
static bool instrumentation()
static bool dataMemberType()
static bool objCLifetime()
static bool addressSpace()
static bool fixedPointType()
static bool vecTernaryOp()
static bool cgFPOptionsRAII()
static bool complexType()
static bool sanitizers()
static bool matrixType()
static bool ptrDiffOp()
static bool fpConstraints()
static bool addHeapAllocSiteMetadata()
static bool mayHaveIntegerOverflow()
static bool tryEmitAsConstant()
static bool scalableVectors()
static bool emitLValueAlignmentAssumption()
static bool incrementProfileCounter()
Represents a scope, including function bodies, compound statements, and the substatements of if/while...
EvalResult is a struct with detailed info about an evaluated expression.
Definition: Expr.h:645
bool has(SanitizerMask K) const
Check if a certain (single) sanitizer is enabled.
Definition: Sanitizers.h:174