clang 24.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
14#include "CIRGenFunction.h"
15#include "CIRGenValue.h"
16
17#include "clang/AST/Expr.h"
21
22#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h"
23#include "mlir/IR/Location.h"
24#include "mlir/IR/Value.h"
25
26#include <cassert>
27#include <utility>
28
29using namespace clang;
30using namespace clang::CIRGen;
31
32namespace {
33
34struct BinOpInfo {
35 mlir::Value lhs;
36 mlir::Value rhs;
37 SourceRange loc;
38 QualType fullType; // Type of operands and result
39 QualType compType; // Type used for computations. Element type
40 // for vectors, otherwise same as FullType.
41 BinaryOperator::Opcode opcode; // Opcode of BinOp to perform
42 FPOptions fpFeatures;
43 const Expr *e; // Entire expr, for error unsupported. May not be binop.
44
45 /// Check if the binop computes a division or a remainder.
46 bool isDivRemOp() const {
47 return opcode == BO_Div || opcode == BO_Rem || opcode == BO_DivAssign ||
48 opcode == BO_RemAssign;
49 }
50
51 /// Check if the binop can result in integer overflow.
52 bool mayHaveIntegerOverflow() const {
53 // Without constant input, we can't rule out overflow.
54 auto lhsci = lhs.getDefiningOp<cir::ConstantOp>();
55 auto rhsci = rhs.getDefiningOp<cir::ConstantOp>();
56 if (!lhsci || !rhsci)
57 return true;
58
60 // TODO(cir): For now we just assume that we might overflow
61 return true;
62 }
63
64 /// Check if at least one operand is a fixed point type. In such cases,
65 /// this operation did not follow usual arithmetic conversion and both
66 /// operands might not be of the same type.
67 bool isFixedPointOp() const {
68 // We cannot simply check the result type since comparison operations
69 // return an int.
70 if (const auto *binOp = llvm::dyn_cast<BinaryOperator>(e)) {
71 QualType lhstype = binOp->getLHS()->getType();
72 QualType rhstype = binOp->getRHS()->getType();
73 return lhstype->isFixedPointType() || rhstype->isFixedPointType();
74 }
75 if (const auto *unop = llvm::dyn_cast<UnaryOperator>(e))
76 return unop->getSubExpr()->getType()->isFixedPointType();
77 return false;
78 }
79};
80
81class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
82 CIRGenFunction &cgf;
83 CIRGenBuilderTy &builder;
84 // Unlike classic codegen we set this to false or use std::exchange to read
85 // the value instead of calling TestAndClearIgnoreResultAssign to make it
86 // explicit when the value is used
87 bool ignoreResultAssign;
88
89public:
90 ScalarExprEmitter(CIRGenFunction &cgf, CIRGenBuilderTy &builder,
91 bool ignoreResultAssign = false)
92 : cgf(cgf), builder(builder), ignoreResultAssign(ignoreResultAssign) {}
93
94 //===--------------------------------------------------------------------===//
95 // Utilities
96 //===--------------------------------------------------------------------===//
97 mlir::Type convertType(QualType ty) { return cgf.convertType(ty); }
98
99 mlir::Value emitComplexToScalarConversion(mlir::Location loc,
100 mlir::Value value, CastKind kind,
101 QualType destTy);
102
103 mlir::Value emitNullValue(QualType ty, mlir::Location loc) {
104 return cgf.cgm.emitNullConstant(ty, loc);
105 }
106
107 mlir::Value emitPromotedValue(mlir::Value result, QualType promotionType) {
108 return builder.createFloatingCast(result, cgf.convertType(promotionType));
109 }
110
111 mlir::Value emitUnPromotedValue(mlir::Value result, QualType exprType) {
112 return builder.createFloatingCast(result, cgf.convertType(exprType));
113 }
114
115 mlir::Value emitPromoted(const Expr *e, QualType promotionType);
116
117 mlir::Value maybePromoteBoolResult(mlir::Value value,
118 mlir::Type dstTy) const {
119 if (mlir::isa<cir::IntType>(dstTy))
120 return builder.createBoolToInt(value, dstTy);
121 if (mlir::isa<cir::BoolType>(dstTy))
122 return value;
123 llvm_unreachable("Can only promote integer or boolean types");
124 }
125
126 //===--------------------------------------------------------------------===//
127 // Visitor Methods
128 //===--------------------------------------------------------------------===//
129
130 mlir::Value Visit(Expr *e) {
131 return StmtVisitor<ScalarExprEmitter, mlir::Value>::Visit(e);
132 }
133
134 mlir::Value VisitStmt(Stmt *s) {
135 llvm_unreachable("Statement passed to ScalarExprEmitter");
136 }
137
138 mlir::Value VisitExpr(Expr *e) {
139 cgf.getCIRGenModule().errorNYI(
140 e->getSourceRange(), "scalar expression kind: ", e->getStmtClassName());
141 return {};
142 }
143
144 mlir::Value VisitConstantExpr(ConstantExpr *e) {
145 // A constant expression of type 'void' generates no code and produces no
146 // value.
147 if (e->getType()->isVoidType())
148 return {};
149
150 if (mlir::Attribute result = ConstantEmitter(cgf).tryEmitConstantExpr(e)) {
151 if (e->isGLValue()) {
152 cgf.cgm.errorNYI(e->getSourceRange(),
153 "ScalarExprEmitter: constant expr GL Value");
154 return {};
155 }
156
157 return builder.getConstant(cgf.getLoc(e->getSourceRange()),
158 mlir::cast<mlir::TypedAttr>(result));
159 }
160
161 cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: constant expr");
162 return {};
163 }
164
165 mlir::Value VisitPackIndexingExpr(PackIndexingExpr *e) {
166 return Visit(e->getSelectedExpr());
167 }
168
169 mlir::Value VisitParenExpr(ParenExpr *pe) { return Visit(pe->getSubExpr()); }
170
171 mlir::Value VisitGenericSelectionExpr(GenericSelectionExpr *ge) {
172 return Visit(ge->getResultExpr());
173 }
174
175 /// Emits the address of the l-value, then loads and returns the result.
176 mlir::Value emitLoadOfLValue(const Expr *e) {
177 LValue lv = cgf.emitLValue(e);
178 // FIXME: add some akin to EmitLValueAlignmentAssumption(E, V);
179 return cgf.emitLoadOfLValue(lv, e->getExprLoc()).getValue();
180 }
181
182 mlir::Value VisitCoawaitExpr(CoawaitExpr *s) {
183 return cgf.emitCoawaitExpr(*s).getValue();
184 }
185
186 mlir::Value VisitCoyieldExpr(CoyieldExpr *e) {
187 return cgf.emitCoyieldExpr(*e).getValue();
188 }
189
190 mlir::Value VisitUnaryCoawait(const UnaryOperator *e) {
191 cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: unary coawait");
192 return {};
193 }
194
195 mlir::Value emitLoadOfLValue(LValue lv, SourceLocation loc) {
196 return cgf.emitLoadOfLValue(lv, loc).getValue();
197 }
198
199 // l-values
200 mlir::Value VisitDeclRefExpr(DeclRefExpr *e) {
201 if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(e))
202 return cgf.emitScalarConstant(constant, e);
203
204 return emitLoadOfLValue(e);
205 }
206
207 mlir::Value VisitAddrLabelExpr(const AddrLabelExpr *e) {
208 auto func = cast<cir::FuncOp>(cgf.curFn);
209 cir::BlockAddrInfoAttr blockInfoAttr = cir::BlockAddrInfoAttr::get(
210 &cgf.getMLIRContext(), func.getSymName(), e->getLabel()->getName());
211 // GotoSolver collects this cir.block_address op after FlattenCFG to keep
212 // the label and wire it as an indirect-branch successor.
213 return cir::BlockAddressOp::create(builder, cgf.getLoc(e->getSourceRange()),
214 cgf.convertType(e->getType()),
215 blockInfoAttr);
216 }
217
218 mlir::Value VisitIntegerLiteral(const IntegerLiteral *e) {
219 mlir::Type type = cgf.convertType(e->getType());
220 return cir::ConstantOp::create(builder, cgf.getLoc(e->getExprLoc()),
221 cir::IntAttr::get(type, e->getValue()));
222 }
223
224 mlir::Value VisitFixedPointLiteral(const FixedPointLiteral *e) {
225 mlir::Type type = cgf.convertType(e->getType());
226 return cir::ConstantOp::create(builder, cgf.getLoc(e->getExprLoc()),
227 cir::IntAttr::get(type, e->getValue()));
228 }
229
230 mlir::Value VisitFloatingLiteral(const FloatingLiteral *e) {
231 mlir::Type type = cgf.convertType(e->getType());
232 assert(mlir::isa<cir::FPTypeInterface>(type) &&
233 "expect floating-point type");
234 return cir::ConstantOp::create(builder, cgf.getLoc(e->getExprLoc()),
235 cir::FPAttr::get(type, e->getValue()));
236 }
237
238 mlir::Value VisitCharacterLiteral(const CharacterLiteral *e) {
239 mlir::Type ty = cgf.convertType(e->getType());
240 // Character literals are always stored in an unsigned (even for signed
241 // char), so allow implicit truncation here.
242 auto intTy = mlir::cast<cir::IntTypeInterface>(ty);
243 llvm::APInt apValue(intTy.getWidth(), e->getValue(),
244 /*isSigned=*/false, /*implicitTrunc=*/true);
245 return cir::ConstantOp::create(builder, cgf.getLoc(e->getExprLoc()),
246 cir::IntAttr::get(ty, apValue));
247 }
248
249 mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
250 return builder.getBool(e->getValue(), cgf.getLoc(e->getExprLoc()));
251 }
252
253 mlir::Value VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *e) {
254 if (e->getType()->isVoidType())
255 return {};
256
257 return emitNullValue(e->getType(), cgf.getLoc(e->getSourceRange()));
258 }
259
260 mlir::Value VisitGNUNullExpr(const GNUNullExpr *e) {
261 return emitNullValue(e->getType(), cgf.getLoc(e->getSourceRange()));
262 }
263
264 mlir::Value VisitOffsetOfExpr(OffsetOfExpr *e);
265
266 mlir::Value VisitSizeOfPackExpr(SizeOfPackExpr *e) {
267 return builder.getConstInt(cgf.getLoc(e->getExprLoc()),
268 convertType(e->getType()), e->getPackLength());
269 }
270 mlir::Value VisitPseudoObjectExpr(PseudoObjectExpr *e) {
271 return cgf.emitPseudoObjectRValue(e).getValue();
272 }
273 mlir::Value VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *e) {
274 cgf.cgm.errorNYI(e->getSourceRange(),
275 "ScalarExprEmitter: sycl unique stable name");
276 return {};
277 }
278 mlir::Value VisitEmbedExpr(EmbedExpr *e) {
279 assert(e->getDataElementCount() == 1);
280 auto it = e->begin();
281 llvm::APInt value = (*it)->getValue();
282 return builder.getConstInt(cgf.getLoc(e->getExprLoc()), value,
284 }
285 mlir::Value VisitOpaqueValueExpr(OpaqueValueExpr *e) {
286 if (e->isGLValue())
287 return emitLoadOfLValue(cgf.getOrCreateOpaqueLValueMapping(e),
288 e->getExprLoc());
289
290 // Otherwise, assume the mapping is the scalar directly.
291 return cgf.getOrCreateOpaqueRValueMapping(e).getValue();
292 }
293
294 mlir::Value VisitObjCSelectorExpr(ObjCSelectorExpr *e) {
295 cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: objc selector");
296 return {};
297 }
298 mlir::Value VisitObjCProtocolExpr(ObjCProtocolExpr *e) {
299 cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: objc protocol");
300 return {};
301 }
302 mlir::Value VisitObjCIVarRefExpr(ObjCIvarRefExpr *e) {
303 cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: objc ivar ref");
304 return {};
305 }
306 mlir::Value VisitObjCMessageExpr(ObjCMessageExpr *e) {
307 cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: objc message");
308 return {};
309 }
310 mlir::Value VisitObjCIsaExpr(ObjCIsaExpr *e) {
311 cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: objc isa");
312 return {};
313 }
314 mlir::Value VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *e) {
315 cgf.cgm.errorNYI(e->getSourceRange(),
316 "ScalarExprEmitter: objc availability check");
317 return {};
318 }
319
320 mlir::Value VisitMatrixSubscriptExpr(MatrixSubscriptExpr *e) {
321 cgf.cgm.errorNYI(e->getSourceRange(),
322 "ScalarExprEmitter: matrix subscript");
323 return {};
324 }
325
326 mlir::Value VisitCastExpr(CastExpr *e);
327 mlir::Value VisitCallExpr(const CallExpr *e);
328
329 mlir::Value VisitStmtExpr(StmtExpr *e) {
330 CIRGenFunction::StmtExprEvaluation eval(cgf);
331 if (e->getType()->isVoidType()) {
332 (void)cgf.emitCompoundStmt(*e->getSubStmt());
333 return {};
334 }
335
336 Address retAlloca =
337 cgf.createMemTemp(e->getType(), cgf.getLoc(e->getSourceRange()));
338 (void)cgf.emitCompoundStmt(*e->getSubStmt(), &retAlloca);
339
340 return cgf.emitLoadOfScalar(cgf.makeAddrLValue(retAlloca, e->getType()),
341 e->getExprLoc());
342 }
343
344 mlir::Value VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
345 ignoreResultAssign = false;
346
347 if (e->getBase()->getType()->isVectorType()) {
349
350 const mlir::Location loc = cgf.getLoc(e->getSourceRange());
351 const mlir::Value vecValue = Visit(e->getBase());
352 const mlir::Value indexValue = Visit(e->getIdx());
353 return cir::VecExtractOp::create(cgf.builder, loc, vecValue, indexValue);
354 }
355 // Just load the lvalue formed by the subscript expression.
356 return emitLoadOfLValue(e);
357 }
358
359 mlir::Value VisitShuffleVectorExpr(ShuffleVectorExpr *e) {
360 if (e->getNumSubExprs() == 2) {
361 // The undocumented form of __builtin_shufflevector.
362 mlir::Value inputVec = Visit(e->getExpr(0));
363 mlir::Value indexVec = Visit(e->getExpr(1));
364 return cir::VecShuffleDynamicOp::create(
365 cgf.builder, cgf.getLoc(e->getSourceRange()), inputVec, indexVec);
366 }
367
368 mlir::Value vec1 = Visit(e->getExpr(0));
369 mlir::Value vec2 = Visit(e->getExpr(1));
370
371 // The documented form of __builtin_shufflevector, where the indices are
372 // a variable number of integer constants. The constants will be stored
373 // in an ArrayAttr.
374 SmallVector<mlir::Attribute, 8> indices;
375 for (unsigned i = 2; i < e->getNumSubExprs(); ++i) {
376 indices.push_back(
377 cir::IntAttr::get(cgf.builder.getSInt64Ty(),
378 e->getExpr(i)
379 ->EvaluateKnownConstInt(cgf.getContext())
380 .getSExtValue()));
381 }
382
383 return cir::VecShuffleOp::create(cgf.builder,
384 cgf.getLoc(e->getSourceRange()),
385 cgf.convertType(e->getType()), vec1, vec2,
386 cgf.builder.getArrayAttr(indices));
387 }
388
389 mlir::Value VisitConvertVectorExpr(ConvertVectorExpr *e) {
390 // __builtin_convertvector is an element-wise cast, and is implemented as a
391 // regular cast. The back end handles casts of vectors correctly.
392 return emitScalarConversion(Visit(e->getSrcExpr()),
393 e->getSrcExpr()->getType(), e->getType(),
394 e->getSourceRange().getBegin());
395 }
396
397 mlir::Value VisitExtVectorElementExpr(Expr *e) { return emitLoadOfLValue(e); }
398
399 mlir::Value VisitMatrixElementExpr(Expr *e) {
400 cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: matrix element");
401 return {};
402 }
403
404 mlir::Value VisitMemberExpr(MemberExpr *e);
405
406 mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
407 return emitLoadOfLValue(e);
408 }
409
410 mlir::Value VisitInitListExpr(InitListExpr *e);
411
412 mlir::Value VisitArrayInitIndexExpr(ArrayInitIndexExpr *e) {
413 assert(cgf.getArrayInitIndex() &&
414 "ArrayInitIndexExpr not inside an ArrayInitLoopExpr?");
415 return cgf.getArrayInitIndex();
416 }
417
418 mlir::Value VisitImplicitValueInitExpr(const ImplicitValueInitExpr *e) {
419 return emitNullValue(e->getType(), cgf.getLoc(e->getSourceRange()));
420 }
421
422 mlir::Value VisitExplicitCastExpr(ExplicitCastExpr *e) {
423 return VisitCastExpr(e);
424 }
425
426 mlir::Value VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *e) {
427 return cgf.cgm.emitNullConstant(e->getType(),
428 cgf.getLoc(e->getSourceRange()));
429 }
430
431 /// Perform a pointer to boolean conversion.
432 mlir::Value emitPointerToBoolConversion(mlir::Value v, QualType qt) {
433 // TODO(cir): comparing the ptr to null is done when lowering CIR to LLVM.
434 // We might want to have a separate pass for these types of conversions.
435 return cgf.getBuilder().createPtrToBoolCast(v);
436 }
437
438 mlir::Value emitFloatToBoolConversion(mlir::Value src, mlir::Location loc) {
439 cir::BoolType boolTy = builder.getBoolTy();
440 return cir::CastOp::create(builder, loc, boolTy,
441 cir::CastKind::float_to_bool, src);
442 }
443
444 mlir::Value emitIntToBoolConversion(mlir::Value srcVal, mlir::Location loc) {
445 // The enumerator of an enum with an integral underlying type is lowered to
446 // that type, which can be bool. In that case the operand is already a
447 // !cir.bool, so return it -- int_to_bool requires a !cir.int source.
448 if (mlir::isa<cir::BoolType>(srcVal.getType()))
449 return srcVal;
450
451 // Because of the type rules of C, we often end up computing a
452 // logical value, then zero extending it to int, then wanting it
453 // as a logical value again.
454 // TODO: optimize this common case here or leave it for later
455 // CIR passes?
456 cir::BoolType boolTy = builder.getBoolTy();
457 return cir::CastOp::create(builder, loc, boolTy, cir::CastKind::int_to_bool,
458 srcVal);
459 }
460
461 /// Convert the specified expression value to a boolean (!cir.bool) truth
462 /// value. This is equivalent to "Val != 0".
463 mlir::Value emitConversionToBool(mlir::Value src, QualType srcType,
464 mlir::Location loc) {
465 assert(srcType.isCanonical() && "EmitScalarConversion strips typedefs");
466
467 if (srcType->isRealFloatingType())
468 return emitFloatToBoolConversion(src, loc);
469
470 if (llvm::isa<MemberPointerType>(srcType)) {
471 cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
472 return builder.getFalse(loc);
473 }
474
475 if (srcType->isIntegerType())
476 return emitIntToBoolConversion(src, loc);
477
478 assert(::mlir::isa<cir::PointerType>(src.getType()));
479 return emitPointerToBoolConversion(src, srcType);
480 }
481
482 // Emit a conversion from the specified type to the specified destination
483 // type, both of which are CIR scalar types.
484 struct ScalarConversionOpts {
485 bool treatBooleanAsSigned;
486 bool emitImplicitIntegerTruncationChecks;
487 bool emitImplicitIntegerSignChangeChecks;
488
489 ScalarConversionOpts()
490 : treatBooleanAsSigned(false),
491 emitImplicitIntegerTruncationChecks(false),
492 emitImplicitIntegerSignChangeChecks(false) {}
493
494 ScalarConversionOpts(clang::SanitizerSet sanOpts)
495 : treatBooleanAsSigned(false),
496 emitImplicitIntegerTruncationChecks(
497 sanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)),
498 emitImplicitIntegerSignChangeChecks(
499 sanOpts.has(SanitizerKind::ImplicitIntegerSignChange)) {}
500 };
501
502 // Conversion from bool, integral, or floating-point to integral or
503 // floating-point. Conversions involving other types are handled elsewhere.
504 // Conversion to bool is handled elsewhere because that's a comparison against
505 // zero, not a simple cast. This handles both individual scalars and vectors.
506 mlir::Value emitScalarCast(mlir::Value src, QualType srcType,
507 QualType dstType, mlir::Type srcTy,
508 mlir::Type dstTy, ScalarConversionOpts opts) {
509 assert(!srcType->isMatrixType() && !dstType->isMatrixType() &&
510 "Internal error: matrix types not handled by this function.");
511 assert(!(mlir::isa<mlir::IntegerType>(srcTy) ||
512 mlir::isa<mlir::IntegerType>(dstTy)) &&
513 "Obsolete code. Don't use mlir::IntegerType with CIR.");
514
515 mlir::Type fullDstTy = dstTy;
516 if (mlir::isa<cir::VectorType>(srcTy) &&
517 mlir::isa<cir::VectorType>(dstTy)) {
518 // Use the element types of the vectors to figure out the CastKind.
519 srcTy = mlir::dyn_cast<cir::VectorType>(srcTy).getElementType();
520 dstTy = mlir::dyn_cast<cir::VectorType>(dstTy).getElementType();
521 }
522
523 std::optional<cir::CastKind> castKind;
524
525 // Start with a null fenv attr. If this is a floating point cast, we will
526 // get the attribute from the builder.
527 cir::FenvAttr fenvAttr;
528
529 if (mlir::isa<cir::BoolType>(srcTy)) {
530 if (opts.treatBooleanAsSigned)
531 cgf.getCIRGenModule().errorNYI("signed bool");
532 if (cgf.getBuilder().isInt(dstTy)) {
533 castKind = cir::CastKind::bool_to_int;
534 } else if (mlir::isa<cir::FPTypeInterface>(dstTy)) {
535 fenvAttr = cgf.getBuilder().getConstrainedFPAttr();
536 castKind = cir::CastKind::bool_to_float;
537 } else {
538 llvm_unreachable("Internal error: Cast to unexpected type");
539 }
540 } else if (cgf.getBuilder().isInt(srcTy)) {
541 if (cgf.getBuilder().isInt(dstTy)) {
542 castKind = cir::CastKind::integral;
543 } else if (mlir::isa<cir::FPTypeInterface>(dstTy)) {
544 fenvAttr = cgf.getBuilder().getConstrainedFPAttr();
545 castKind = cir::CastKind::int_to_float;
546 } else if (mlir::isa<cir::BoolType>(dstTy)) {
547 castKind = cir::CastKind::int_to_bool;
548 } else {
549 llvm_unreachable("Internal error: Cast to unexpected type");
550 }
551 } else if (mlir::isa<cir::FPTypeInterface>(srcTy)) {
552 fenvAttr = cgf.getBuilder().getConstrainedFPAttr();
553 if (cgf.getBuilder().isInt(dstTy)) {
554 // If we can't recognize overflow as undefined behavior, assume that
555 // overflow saturates. This protects against normal optimizations if we
556 // are compiling with non-standard FP semantics.
557 if (!cgf.cgm.getCodeGenOpts().StrictFloatCastOverflow)
558 cgf.getCIRGenModule().errorNYI("strict float cast overflow");
559 castKind = cir::CastKind::float_to_int;
560 } else if (mlir::isa<cir::FPTypeInterface>(dstTy)) {
561 // TODO: split this to createFPExt/createFPTrunc
562 return builder.createFloatingCast(src, fullDstTy);
563 } else if (mlir::isa<cir::BoolType>(dstTy)) {
564 castKind = cir::CastKind::float_to_bool;
565 } else {
566 llvm_unreachable("Internal error: Cast to unexpected type");
567 }
568 } else {
569 llvm_unreachable("Internal error: Cast from unexpected type");
570 }
571
572 assert(castKind.has_value() && "Internal error: CastKind not set.");
573 return builder.createOrFold<cir::CastOp>(src.getLoc(), fullDstTy, *castKind,
574 src, fenvAttr);
575 }
576
577 mlir::Value
578 VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e) {
579 return Visit(e->getReplacement());
580 }
581
582 mlir::Value VisitVAArgExpr(VAArgExpr *ve) {
583 QualType ty = ve->getType();
584
585 if (ty->isVariablyModifiedType()) {
586 cgf.cgm.errorNYI(ve->getSourceRange(),
587 "variably modified types in varargs");
588 }
589
590 return cgf.emitVAArg(ve);
591 }
592
593 mlir::Value VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *e) {
594 return Visit(e->getSemanticForm());
595 }
596
597 mlir::Value VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *e);
598 mlir::Value
599 VisitAbstractConditionalOperator(const AbstractConditionalOperator *e);
600
601 // Unary Operators.
602 mlir::Value VisitUnaryPrePostIncDec(const UnaryOperator *e) {
603 LValue lv = cgf.emitLValue(e->getSubExpr());
604 return emitScalarPrePostIncDec(e, lv);
605 }
606 mlir::Value VisitUnaryPostDec(const UnaryOperator *e) {
607 return VisitUnaryPrePostIncDec(e);
608 }
609 mlir::Value VisitUnaryPostInc(const UnaryOperator *e) {
610 return VisitUnaryPrePostIncDec(e);
611 }
612 mlir::Value VisitUnaryPreDec(const UnaryOperator *e) {
613 return VisitUnaryPrePostIncDec(e);
614 }
615 mlir::Value VisitUnaryPreInc(const UnaryOperator *e) {
616 return VisitUnaryPrePostIncDec(e);
617 }
618 mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv) {
619 if (cgf.getLangOpts().OpenMP)
620 cgf.cgm.errorNYI(e->getSourceRange(), "inc/dec OpenMP");
621
622 QualType type = e->getSubExpr()->getType();
623
624 mlir::Value value;
625 mlir::Value input;
626
627 if (type->getAs<AtomicType>()) {
628 cgf.cgm.errorNYI(e->getSourceRange(), "Atomic inc/dec");
629 // TODO(cir): This is not correct, but it will produce reasonable code
630 // until atomic operations are implemented.
631 value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getValue();
632 input = value;
633 } else {
634 value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getValue();
635 input = value;
636 }
637
638 // NOTE: When possible, more frequent cases are handled first.
639
640 // Special case of integer increment that we have to check first: bool++.
641 // Due to promotion rules, we get:
642 // bool++ -> bool = bool + 1
643 // -> bool = (int)bool + 1
644 // -> bool = ((int)bool + 1 != 0)
645 // An interesting aspect of this is that increment is always true.
646 // Decrement does not have this property.
647 if (e->isIncrementOp() && type->isBooleanType()) {
648 value = builder.getTrue(cgf.getLoc(e->getExprLoc()));
649 } else if (type->isIntegerType()) {
650 QualType promotedType;
651 [[maybe_unused]] bool canPerformLossyDemotionCheck = false;
652 if (cgf.getContext().isPromotableIntegerType(type)) {
653 promotedType = cgf.getContext().getPromotedIntegerType(type);
654 assert(promotedType != type && "Shouldn't promote to the same type.");
655 canPerformLossyDemotionCheck = true;
656 canPerformLossyDemotionCheck &=
657 cgf.getContext().getCanonicalType(type) !=
658 cgf.getContext().getCanonicalType(promotedType);
659 canPerformLossyDemotionCheck &=
660 type->isIntegerType() && promotedType->isIntegerType();
661
662 // TODO(cir): Currently, we store bitwidths in CIR types only for
663 // integers. This might also be required for other types.
664
665 assert(
666 (!canPerformLossyDemotionCheck ||
667 type->isSignedIntegerOrEnumerationType() ||
668 promotedType->isSignedIntegerOrEnumerationType() ||
669 mlir::cast<cir::IntType>(cgf.convertType(type)).getWidth() ==
670 mlir::cast<cir::IntType>(cgf.convertType(type)).getWidth()) &&
671 "The following check expects that if we do promotion to different "
672 "underlying canonical type, at least one of the types (either "
673 "base or promoted) will be signed, or the bitwidths will match.");
674 }
675
677 if (e->canOverflow() && type->isSignedIntegerOrEnumerationType()) {
678 value = emitIncDecConsiderOverflowBehavior(e, value);
679 } else {
680 // NOTE(CIR): clang calls CreateAdd but folds this to a unary op
681 value = emitIncOrDec(e, input, /*nsw=*/false);
682 }
683 } else if (const PointerType *ptr = type->getAs<PointerType>()) {
684 QualType type = ptr->getPointeeType();
685 if (const VariableArrayType *vla =
686 cgf.getContext().getAsVariableArrayType(type)) {
687 mlir::Location loc = cgf.getLoc(e->getSourceRange());
688 mlir::Value numElts = cgf.getVLASize(vla).numElts;
689 if (!e->isIncrementOp())
690 numElts = cgf.getBuilder().createNeg(loc, numElts, /*nsw=*/true);
692 value = cgf.getBuilder().createPtrStride(loc, value, numElts);
693 } else {
694 // For everything else, we can just do a simple increment.
695 mlir::Location loc = cgf.getLoc(e->getSourceRange());
696 int amount = e->isIncrementOp() ? 1 : -1;
697 mlir::Value amt = builder.getSInt32(amount, loc);
699 value = builder.createPtrStride(loc, value, amt);
700 }
701 } else if (type->isVectorType()) {
702 if (type->hasIntegerRepresentation()) {
703 value = emitIncOrDec(e, input, /*nsw=*/false);
704 } else {
705 cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec vector of float");
706 return {};
707 }
708 } else if (type->isRealFloatingType()) {
709 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, e);
710
711 if (type->isHalfType() &&
712 !cgf.getContext().getLangOpts().NativeHalfType) {
713 cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec half");
714 return {};
715 }
716
717 if (mlir::isa<cir::SingleType, cir::DoubleType, cir::LongDoubleType>(
718 value.getType())) {
719 mlir::Location loc = cgf.getLoc(e->getExprLoc());
720 auto fpType = mlir::cast<cir::FPTypeInterface>(value.getType());
721 mlir::Value amount = builder.getConstFP(
722 loc, value.getType(), llvm::APFloat(fpType.getFloatSemantics(), 1));
723 value = e->isIncrementOp() ? builder.createFAdd(loc, value, amount)
724 : builder.createFSub(loc, value, amount);
725 } else {
726 cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec other fp type");
727 return {};
728 }
729 } else if (type->isFixedPointType()) {
730 cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec other fixed point");
731 return {};
732 } else {
733 assert(type->castAs<ObjCObjectPointerType>());
734 cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec ObjectiveC pointer");
735 return {};
736 }
737
738 CIRGenFunction::SourceLocRAIIObject sourceloc{
739 cgf, cgf.getLoc(e->getSourceRange())};
740
741 // Store the updated result through the lvalue
742 if (lv.isBitField())
743 value = cgf.emitStoreThroughBitfieldLValue(RValue::get(value), lv);
744 else
745 cgf.emitStoreThroughLValue(RValue::get(value), lv);
746
747 // If this is a postinc, return the value read from memory, otherwise use
748 // the updated value.
749 return e->isPrefix() ? value : input;
750 }
751
752 mlir::Value emitIncDecConsiderOverflowBehavior(const UnaryOperator *e,
753 mlir::Value inVal) {
754 switch (cgf.getLangOpts().getSignedOverflowBehavior()) {
755 case LangOptions::SOB_Defined:
756 return emitIncOrDec(e, inVal, /*nsw=*/false);
757 case LangOptions::SOB_Undefined:
759 return emitIncOrDec(e, inVal, /*nsw=*/true);
760 case LangOptions::SOB_Trapping:
761 if (!e->canOverflow())
762 return emitIncOrDec(e, inVal, /*nsw=*/true);
763 cgf.cgm.errorNYI(e->getSourceRange(), "inc/def overflow SOB_Trapping");
764 return {};
765 }
766 llvm_unreachable("Unexpected signed overflow behavior kind");
767 }
768
769 mlir::Value VisitUnaryAddrOf(const UnaryOperator *e) {
770 if (llvm::isa<MemberPointerType>(e->getType()))
771 return cgf.cgm.emitMemberPointerConstant(e);
772
773 return cgf.emitLValue(e->getSubExpr()).getPointer();
774 }
775
776 mlir::Value VisitUnaryDeref(const UnaryOperator *e) {
777 if (e->getType()->isVoidType())
778 return Visit(e->getSubExpr()); // the actual value should be unused
779 return emitLoadOfLValue(e);
780 }
781
782 mlir::Value VisitUnaryPlus(const UnaryOperator *e) {
783 QualType promotionType = getPromotionType(e->getSubExpr()->getType());
784 mlir::Value result = VisitUnaryPlus(e, promotionType);
785 if (result && !promotionType.isNull())
786 return emitUnPromotedValue(result, e->getType());
787 return result;
788 }
789
790 mlir::Value VisitUnaryPlus(const UnaryOperator *e, QualType promotionType) {
791 ignoreResultAssign = false;
792 if (!promotionType.isNull())
793 return cgf.emitPromotedScalarExpr(e->getSubExpr(), promotionType);
794 return Visit(e->getSubExpr());
795 }
796
797 mlir::Value VisitUnaryMinus(const UnaryOperator *e) {
798 QualType promotionType = getPromotionType(e->getSubExpr()->getType());
799 mlir::Value result = VisitUnaryMinus(e, promotionType);
800 if (result && !promotionType.isNull())
801 return emitUnPromotedValue(result, e->getType());
802 return result;
803 }
804
805 mlir::Value VisitUnaryMinus(const UnaryOperator *e, QualType promotionType) {
806 ignoreResultAssign = false;
807 mlir::Value operand;
808 if (!promotionType.isNull())
809 operand = cgf.emitPromotedScalarExpr(e->getSubExpr(), promotionType);
810 else
811 operand = Visit(e->getSubExpr());
812
813 mlir::Location loc = cgf.getLoc(e->getSourceRange().getBegin());
814
815 if (cir::isFPOrVectorOfFPType(operand.getType()))
816 return builder.createOrFold<cir::FNegOp>(loc, operand);
817
818 // TODO(cir): We might have to change this to support overflow trapping.
819 // Classic codegen routes unary minus through emitSub to ensure
820 // that the overflow behavior is handled correctly.
821 bool nsw = e->getType()->isSignedIntegerType() &&
822 cgf.getLangOpts().getSignedOverflowBehavior() !=
823 LangOptions::SOB_Defined;
824
825 return builder.createOrFold<cir::MinusOp>(loc, operand, nsw);
826 }
827
828 mlir::Value emitIncOrDec(const UnaryOperator *e, mlir::Value input,
829 bool nsw = false) {
830 mlir::Location loc = cgf.getLoc(e->getSourceRange().getBegin());
831 return e->isIncrementOp()
832 ? builder.createOrFold<cir::IncOp>(loc, input, nsw)
833 : builder.createOrFold<cir::DecOp>(loc, input, nsw);
834 }
835
836 mlir::Value VisitUnaryNot(const UnaryOperator *e) {
837 ignoreResultAssign = false;
838 mlir::Value op = Visit(e->getSubExpr());
839 return builder.createOrFold<cir::NotOp>(
840 cgf.getLoc(e->getSourceRange().getBegin()), op);
841 }
842
843 mlir::Value VisitUnaryLNot(const UnaryOperator *e);
844
845 mlir::Value VisitUnaryReal(const UnaryOperator *e);
846 mlir::Value VisitUnaryImag(const UnaryOperator *e);
847 mlir::Value VisitRealImag(const UnaryOperator *e,
848 QualType promotionType = QualType());
849
850 mlir::Value VisitUnaryExtension(const UnaryOperator *e) {
851 return Visit(e->getSubExpr());
852 }
853
854 // C++
855 mlir::Value VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *e) {
856 cgf.cgm.errorNYI(e->getSourceRange(),
857 "ScalarExprEmitter: materialize temporary");
858 return {};
859 }
860 mlir::Value VisitSourceLocExpr(SourceLocExpr *e) {
861 ASTContext &ctx = cgf.getContext();
862 APValue evaluated =
863 e->EvaluateInContext(ctx, cgf.curSourceLocExprScope.getDefaultExpr());
864 mlir::Attribute attribute = ConstantEmitter(cgf).emitAbstract(
865 e->getLocation(), evaluated, e->getType());
866 mlir::TypedAttr typedAttr = mlir::cast<mlir::TypedAttr>(attribute);
867 return cir::ConstantOp::create(builder, cgf.getLoc(e->getExprLoc()),
868 typedAttr);
869 }
870 mlir::Value VisitCXXDefaultArgExpr(CXXDefaultArgExpr *dae) {
871 CIRGenFunction::CXXDefaultArgExprScope scope(cgf, dae);
872 return Visit(dae->getExpr());
873 }
874 mlir::Value VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
875 CIRGenFunction::CXXDefaultInitExprScope scope(cgf, die);
876 return Visit(die->getExpr());
877 }
878
879 mlir::Value VisitCXXThisExpr(CXXThisExpr *te) { return cgf.loadCXXThis(); }
880
881 mlir::Value VisitExprWithCleanups(ExprWithCleanups *e);
882 mlir::Value VisitCXXNewExpr(const CXXNewExpr *e) {
883 return cgf.emitCXXNewExpr(e);
884 }
885 mlir::Value VisitCXXDeleteExpr(const CXXDeleteExpr *e) {
886 cgf.emitCXXDeleteExpr(e);
887 return {};
888 }
889 mlir::Value VisitTypeTraitExpr(const TypeTraitExpr *e) {
890 // We diverge slightly from classic codegen here because CIR has stricter
891 // typing. In LLVM IR, constant folding covers up some potential type
892 // mismatches such as bool-to-int conversions that would fail the verifier
893 // in CIR. To make things work, we need to be sure we only emit a bool value
894 // if the expression type is bool.
895 mlir::Location loc = cgf.getLoc(e->getExprLoc());
896 if (e->isStoredAsBoolean()) {
897 if (e->getType()->isBooleanType())
898 return builder.getBool(e->getBoolValue(), loc);
899 assert(e->getType()->isIntegerType() &&
900 "Expected int type for TypeTraitExpr");
901 return builder.getConstInt(loc, cgf.convertType(e->getType()),
902 (uint64_t)e->getBoolValue());
903 }
904 return builder.getConstInt(loc, e->getAPValue().getInt());
905 }
906 mlir::Value
907 VisitConceptSpecializationExpr(const ConceptSpecializationExpr *e) {
908 return builder.getBool(e->isSatisfied(), cgf.getLoc(e->getExprLoc()));
909 }
910 mlir::Value VisitRequiresExpr(const RequiresExpr *e) {
911 return builder.getBool(e->isSatisfied(), cgf.getLoc(e->getExprLoc()));
912 }
913 mlir::Value VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *e) {
914 mlir::Type type = cgf.convertType(e->getType());
915 mlir::Location loc = cgf.getLoc(e->getExprLoc());
916 return builder.getConstInt(loc, type, e->getValue());
917 }
918 mlir::Value VisitExpressionTraitExpr(const ExpressionTraitExpr *e) {
919 return builder.getBool(e->getValue(), cgf.getLoc(e->getExprLoc()));
920 }
921 mlir::Value VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *e) {
922 cgf.cgm.errorNYI(e->getSourceRange(),
923 "ScalarExprEmitter: cxx pseudo destructor");
924 return {};
925 }
926 mlir::Value VisitCXXThrowExpr(const CXXThrowExpr *e) {
927 cgf.emitCXXThrowExpr(e);
928 return {};
929 }
930
931 mlir::Value VisitCXXNoexceptExpr(CXXNoexceptExpr *e) {
932 return builder.getBool(e->getValue(), cgf.getLoc(e->getExprLoc()));
933 }
934
935 /// Emit a conversion from the specified type to the specified destination
936 /// type, both of which are CIR scalar types.
937 /// TODO: do we need ScalarConversionOpts here? Should be done in another
938 /// pass.
939 mlir::Value
940 emitScalarConversion(mlir::Value src, QualType srcType, QualType dstType,
941 SourceLocation loc,
942 ScalarConversionOpts opts = ScalarConversionOpts()) {
943 // All conversions involving fixed point types should be handled by the
944 // emitFixedPoint family functions. This is done to prevent bloating up
945 // this function more, and although fixed point numbers are represented by
946 // integers, we do not want to follow any logic that assumes they should be
947 // treated as integers.
948 // TODO(leonardchan): When necessary, add another if statement checking for
949 // conversions to fixed point types from other types.
950 // conversions to fixed point types from other types.
951 if (srcType->isFixedPointType() || dstType->isFixedPointType()) {
952 cgf.getCIRGenModule().errorNYI(loc, "fixed point conversions");
953 return {};
954 }
955
956 srcType = srcType.getCanonicalType();
957 dstType = dstType.getCanonicalType();
958 if (srcType == dstType) {
959 if (opts.emitImplicitIntegerSignChangeChecks)
960 cgf.getCIRGenModule().errorNYI(loc,
961 "implicit integer sign change checks");
962 return src;
963 }
964
965 if (dstType->isVoidType())
966 return {};
967
968 mlir::Type mlirSrcType = src.getType();
969
970 // Handle conversions to bool first, they are special: comparisons against
971 // 0.
972 if (dstType->isBooleanType())
973 return emitConversionToBool(src, srcType, cgf.getLoc(loc));
974
975 mlir::Type mlirDstType = cgf.convertType(dstType);
976
977 if (srcType->isHalfType() &&
978 !cgf.getContext().getLangOpts().NativeHalfType) {
979 // Cast to FP using the intrinsic if the half type itself isn't supported.
980 if (!mlir::isa<cir::FPTypeInterface>(mlirDstType)) {
981 // Cast to other types through float, using FPExt, depending on whether
982 // the half type itself is supported (as opposed to operations on half,
983 // available with NativeHalfType).
984 src = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, src,
985 cgf.floatTy);
986 srcType = cgf.getContext().FloatTy;
987 mlirSrcType = cgf.floatTy;
988 }
989 }
990
991 // TODO(cir): LLVM codegen ignore conversions like int -> uint,
992 // is there anything to be done for CIR here?
993 if (mlirSrcType == mlirDstType) {
994 if (opts.emitImplicitIntegerSignChangeChecks)
995 cgf.getCIRGenModule().errorNYI(loc,
996 "implicit integer sign change checks");
997 return src;
998 }
999
1000 // Handle pointer conversions next: pointers can only be converted to/from
1001 // other pointers and integers. Check for pointer types in terms of LLVM, as
1002 // some native types (like Obj-C id) may map to a pointer type.
1003 if (auto dstPT = dyn_cast<cir::PointerType>(mlirDstType)) {
1004 cgf.getCIRGenModule().errorNYI(loc, "pointer casts");
1005 return builder.getNullPtr(dstPT, src.getLoc());
1006 }
1007
1008 if (isa<cir::PointerType>(mlirSrcType)) {
1009 // Must be an ptr to int cast.
1010 assert(isa<cir::IntType>(mlirDstType) && "not ptr->int?");
1011 return builder.createPtrToInt(src, mlirDstType);
1012 }
1013
1014 // A scalar can be splatted to an extended vector of the same element type
1015 if (dstType->isExtVectorType() && !srcType->isVectorType()) {
1016 // Sema should add casts to make sure that the source expression's type
1017 // is the same as the vector's element type (sans qualifiers)
1018 assert(dstType->castAs<ExtVectorType>()->getElementType().getTypePtr() ==
1019 srcType.getTypePtr() &&
1020 "Splatted expr doesn't match with vector element type?");
1021
1022 cgf.getCIRGenModule().errorNYI(loc, "vector splatting");
1023 return {};
1024 }
1025
1026 if (srcType->isMatrixType() && dstType->isMatrixType()) {
1027 cgf.getCIRGenModule().errorNYI(loc,
1028 "matrix type to matrix type conversion");
1029 return {};
1030 }
1031 assert(!srcType->isMatrixType() && !dstType->isMatrixType() &&
1032 "Internal error: conversion between matrix type and scalar type");
1033
1034 // Finally, we have the arithmetic types or vectors of arithmetic types.
1035 mlir::Value res = nullptr;
1036 mlir::Type resTy = mlirDstType;
1037
1038 res = emitScalarCast(src, srcType, dstType, mlirSrcType, mlirDstType, opts);
1039
1040 if (mlirDstType != resTy) {
1041 res = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, res,
1042 resTy);
1043 }
1044
1045 if (opts.emitImplicitIntegerTruncationChecks)
1046 cgf.getCIRGenModule().errorNYI(loc, "implicit integer truncation checks");
1047
1048 if (opts.emitImplicitIntegerSignChangeChecks)
1049 cgf.getCIRGenModule().errorNYI(loc,
1050 "implicit integer sign change checks");
1051
1052 return res;
1053 }
1054
1055 BinOpInfo emitBinOps(const BinaryOperator *e,
1056 QualType promotionType = QualType()) {
1057 ignoreResultAssign = false;
1058 BinOpInfo result;
1059 result.lhs = cgf.emitPromotedScalarExpr(e->getLHS(), promotionType);
1060 result.rhs = cgf.emitPromotedScalarExpr(e->getRHS(), promotionType);
1061 if (!promotionType.isNull())
1062 result.fullType = promotionType;
1063 else
1064 result.fullType = e->getType();
1065 result.compType = result.fullType;
1066 if (const auto *vecType = result.fullType->getAs<VectorType>())
1067 result.compType = vecType->getElementType();
1068 result.opcode = e->getOpcode();
1069 result.loc = e->getSourceRange();
1070 result.fpFeatures = e->getFPFeaturesInEffect(cgf.getLangOpts());
1071 result.e = e;
1072 return result;
1073 }
1074
1075 mlir::Value emitMul(const BinOpInfo &ops);
1076 mlir::Value emitDiv(const BinOpInfo &ops);
1077 mlir::Value emitRem(const BinOpInfo &ops);
1078 mlir::Value emitAdd(const BinOpInfo &ops);
1079 mlir::Value emitSub(const BinOpInfo &ops);
1080 mlir::Value emitShl(const BinOpInfo &ops);
1081 mlir::Value emitShr(const BinOpInfo &ops);
1082 mlir::Value emitAnd(const BinOpInfo &ops);
1083 mlir::Value emitXor(const BinOpInfo &ops);
1084 mlir::Value emitOr(const BinOpInfo &ops);
1085
1086 LValue emitCompoundAssignLValue(
1087 const CompoundAssignOperator *e,
1088 mlir::Value (ScalarExprEmitter::*f)(const BinOpInfo &),
1089 mlir::Value &result);
1090 mlir::Value
1091 emitCompoundAssign(const CompoundAssignOperator *e,
1092 mlir::Value (ScalarExprEmitter::*f)(const BinOpInfo &));
1093
1094 // TODO(cir): Candidate to be in a common AST helper between CIR and LLVM
1095 // codegen.
1096 QualType getPromotionType(QualType ty) {
1097 const clang::ASTContext &ctx = cgf.getContext();
1098 if (auto *complexTy = ty->getAs<ComplexType>()) {
1099 QualType elementTy = complexTy->getElementType();
1100 if (elementTy.UseExcessPrecision(ctx))
1101 return ctx.getComplexType(ctx.FloatTy);
1102 }
1103
1104 if (ty.UseExcessPrecision(cgf.getContext())) {
1105 if (auto *vt = ty->getAs<VectorType>()) {
1106 unsigned numElements = vt->getNumElements();
1107 return ctx.getVectorType(ctx.FloatTy, numElements, vt->getVectorKind());
1108 }
1109 return cgf.getContext().FloatTy;
1110 }
1111
1112 return QualType();
1113 }
1114
1115// Binary operators and binary compound assignment operators.
1116#define HANDLEBINOP(OP) \
1117 mlir::Value VisitBin##OP(const BinaryOperator *e) { \
1118 QualType promotionTy = getPromotionType(e->getType()); \
1119 auto result = emit##OP(emitBinOps(e, promotionTy)); \
1120 if (result && !promotionTy.isNull()) \
1121 result = emitUnPromotedValue(result, e->getType()); \
1122 return result; \
1123 } \
1124 mlir::Value VisitBin##OP##Assign(const CompoundAssignOperator *e) { \
1125 return emitCompoundAssign(e, &ScalarExprEmitter::emit##OP); \
1126 }
1127
1128 HANDLEBINOP(Mul)
1129 HANDLEBINOP(Div)
1130 HANDLEBINOP(Rem)
1131 HANDLEBINOP(Add)
1132 HANDLEBINOP(Sub)
1133 HANDLEBINOP(Shl)
1134 HANDLEBINOP(Shr)
1136 HANDLEBINOP(Xor)
1138#undef HANDLEBINOP
1139
1140 mlir::Value emitCmp(const BinaryOperator *e) {
1141 ignoreResultAssign = false;
1142 const mlir::Location loc = cgf.getLoc(e->getExprLoc());
1143 mlir::Value result;
1144 QualType lhsTy = e->getLHS()->getType();
1145 QualType rhsTy = e->getRHS()->getType();
1146
1147 auto clangCmpToCIRCmp =
1148 [](clang::BinaryOperatorKind clangCmp) -> cir::CmpOpKind {
1149 switch (clangCmp) {
1150 case BO_LT:
1151 return cir::CmpOpKind::lt;
1152 case BO_GT:
1153 return cir::CmpOpKind::gt;
1154 case BO_LE:
1155 return cir::CmpOpKind::le;
1156 case BO_GE:
1157 return cir::CmpOpKind::ge;
1158 case BO_EQ:
1159 return cir::CmpOpKind::eq;
1160 case BO_NE:
1161 return cir::CmpOpKind::ne;
1162 default:
1163 llvm_unreachable("unsupported comparison kind for cir.cmp");
1164 }
1165 };
1166
1167 cir::CmpOpKind kind = clangCmpToCIRCmp(e->getOpcode());
1168 if (lhsTy->getAs<MemberPointerType>()) {
1170 assert(e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE);
1171 mlir::Value lhs = cgf.emitScalarExpr(e->getLHS());
1172 mlir::Value rhs = cgf.emitScalarExpr(e->getRHS());
1173 result = builder.createCompare(loc, kind, lhs, rhs);
1174 } else if (!lhsTy->isAnyComplexType() && !rhsTy->isAnyComplexType()) {
1175 BinOpInfo boInfo = emitBinOps(e);
1176 mlir::Value lhs = boInfo.lhs;
1177 mlir::Value rhs = boInfo.rhs;
1178
1179 if (lhsTy->isVectorType()) {
1180 if (!e->getType()->isVectorType()) {
1181 // If AltiVec, the comparison results in a numeric type, so we use
1182 // intrinsics comparing vectors and giving 0 or 1 as a result
1183 cgf.cgm.errorNYI(loc, "AltiVec comparison");
1184 } else {
1185 // Other kinds of vectors. Element-wise comparison returning
1186 // a vector.
1187 result = cir::VecCmpOp::create(builder, cgf.getLoc(boInfo.loc),
1188 cgf.convertType(boInfo.fullType), kind,
1189 boInfo.lhs, boInfo.rhs);
1190 }
1191 } else if (boInfo.isFixedPointOp()) {
1193 cgf.cgm.errorNYI(loc, "fixed point comparisons");
1194 result = builder.getBool(false, loc);
1195 } else {
1196 // integers and pointers
1197 if (cgf.cgm.getCodeGenOpts().StrictVTablePointers &&
1198 mlir::isa<cir::PointerType>(lhs.getType()) &&
1199 mlir::isa<cir::PointerType>(rhs.getType())) {
1200 cgf.cgm.errorNYI(loc, "strict vtable pointer comparisons");
1201 }
1202 result = builder.createCompare(loc, kind, lhs, rhs);
1203 }
1204 } else {
1205 assert((e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE) &&
1206 "Complex Comparison: can only be an equality comparison");
1207
1208 mlir::Value lhs;
1209 if (lhsTy->isAnyComplexType()) {
1210 lhs = cgf.emitComplexExpr(e->getLHS());
1211 } else {
1212 mlir::Value lhsReal = Visit(e->getLHS());
1213 mlir::Value lhsImag = builder.getNullValue(convertType(lhsTy), loc);
1214 lhs = builder.createComplexCreate(loc, lhsReal, lhsImag);
1215 }
1216
1217 mlir::Value rhs;
1218 if (rhsTy->isAnyComplexType()) {
1219 rhs = cgf.emitComplexExpr(e->getRHS());
1220 } else {
1221 mlir::Value rhsReal = Visit(e->getRHS());
1222 mlir::Value rhsImag = builder.getNullValue(convertType(rhsTy), loc);
1223 rhs = builder.createComplexCreate(loc, rhsReal, rhsImag);
1224 }
1225
1226 result = builder.createCompare(loc, kind, lhs, rhs);
1227 }
1228
1229 return emitScalarConversion(result, cgf.getContext().BoolTy, e->getType(),
1230 e->getExprLoc());
1231 }
1232
1233// Comparisons.
1234#define VISITCOMP(CODE) \
1235 mlir::Value VisitBin##CODE(const BinaryOperator *E) { return emitCmp(E); }
1236 VISITCOMP(LT)
1237 VISITCOMP(GT)
1238 VISITCOMP(LE)
1239 VISITCOMP(GE)
1240 VISITCOMP(EQ)
1241 VISITCOMP(NE)
1242#undef VISITCOMP
1243
1244 mlir::Value VisitBinAssign(const BinaryOperator *e) {
1245 const bool ignore = std::exchange(ignoreResultAssign, false);
1246
1247 mlir::Value rhs;
1248 LValue lhs;
1249
1250 switch (e->getLHS()->getType().getObjCLifetime()) {
1256 break;
1258 // __block variables need to have the rhs evaluated first, plus this
1259 // should improve codegen just a little.
1260 rhs = Visit(e->getRHS());
1262 // TODO(cir): This needs to be emitCheckedLValue() once we support
1263 // sanitizers
1264 lhs = cgf.emitLValue(e->getLHS());
1265
1266 // Store the value into the LHS. Bit-fields are handled specially because
1267 // the result is altered by the store, i.e., [C99 6.5.16p1]
1268 // 'An assignment expression has the value of the left operand after the
1269 // assignment...'.
1270 if (lhs.isBitField()) {
1272 cgf, cgf.getLoc(e->getSourceRange())};
1273 rhs = cgf.emitStoreThroughBitfieldLValue(RValue::get(rhs), lhs);
1274 } else {
1275 cgf.emitNullabilityCheck(lhs, rhs, e->getExprLoc());
1277 cgf, cgf.getLoc(e->getSourceRange())};
1278 cgf.emitStoreThroughLValue(RValue::get(rhs), lhs);
1279 }
1280 }
1281
1282 // If the result is clearly ignored, return now.
1283 if (ignore)
1284 return nullptr;
1285
1286 // The result of an assignment in C is the assigned r-value.
1287 if (!cgf.getLangOpts().CPlusPlus)
1288 return rhs;
1289
1290 // If the lvalue is non-volatile, return the computed value of the
1291 // assignment.
1292 if (!lhs.isVolatile())
1293 return rhs;
1294
1295 // Otherwise, reload the value.
1296 return emitLoadOfLValue(lhs, e->getExprLoc());
1297 }
1298
1299 mlir::Value VisitBinComma(const BinaryOperator *e) {
1300 cgf.emitIgnoredExpr(e->getLHS());
1301 // NOTE: We don't need to EnsureInsertPoint() like LLVM codegen.
1302 return Visit(e->getRHS());
1303 }
1304
1305 mlir::Value VisitBinLAnd(const clang::BinaryOperator *e) {
1306 if (e->getType()->isVectorType()) {
1307 mlir::Location loc = cgf.getLoc(e->getExprLoc());
1308 mlir::Type lhsTy = cgf.convertType(e->getLHS()->getType());
1309 mlir::Value zeroVec = builder.getNullValue(lhsTy, loc);
1310
1311 mlir::Value lhs = Visit(e->getLHS());
1312 mlir::Value rhs = Visit(e->getRHS());
1313
1314 auto cmpOpKind = cir::CmpOpKind::ne;
1315 mlir::Type resTy = cgf.convertType(e->getType());
1316 lhs = cir::VecCmpOp::create(builder, loc, resTy, cmpOpKind, lhs, zeroVec);
1317 rhs = cir::VecCmpOp::create(builder, loc, resTy, cmpOpKind, rhs, zeroVec);
1318 mlir::Value vecOr = builder.createAnd(loc, lhs, rhs);
1319 return builder.createIntCast(vecOr, resTy);
1320 }
1321
1323 mlir::Type resTy = cgf.convertType(e->getType());
1324 mlir::Location loc = cgf.getLoc(e->getExprLoc());
1325
1326 CIRGenFunction::ConditionalEvaluation eval(cgf);
1327
1328 mlir::Value lhsCondV = cgf.evaluateExprAsBool(e->getLHS());
1329 auto resOp = cir::TernaryOp::create(
1330 builder, loc, lhsCondV, /*trueBuilder=*/
1331 [&](mlir::OpBuilder &b, mlir::Location loc) {
1332 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1333 b.getInsertionBlock()};
1334 cgf.curLexScope->setAsTernary();
1335 mlir::Value res = cgf.evaluateExprAsBool(e->getRHS());
1336 lexScope.forceCleanup({&res});
1337 cir::YieldOp::create(b, loc, res);
1338 },
1339 /*falseBuilder*/
1340 [&](mlir::OpBuilder &b, mlir::Location loc) {
1341 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1342 b.getInsertionBlock()};
1343 cgf.curLexScope->setAsTernary();
1344 auto res = cir::ConstantOp::create(b, loc, builder.getFalseAttr());
1345 cir::YieldOp::create(b, loc, res.getRes());
1346 });
1347 return maybePromoteBoolResult(resOp.getResult(), resTy);
1348 }
1349
1350 mlir::Value VisitBinLOr(const clang::BinaryOperator *e) {
1351 if (e->getType()->isVectorType()) {
1352 mlir::Location loc = cgf.getLoc(e->getExprLoc());
1353 mlir::Type lhsTy = cgf.convertType(e->getLHS()->getType());
1354 mlir::Value zeroVec = builder.getNullValue(lhsTy, loc);
1355
1356 mlir::Value lhs = Visit(e->getLHS());
1357 mlir::Value rhs = Visit(e->getRHS());
1358
1359 auto cmpOpKind = cir::CmpOpKind::ne;
1360 mlir::Type resTy = cgf.convertType(e->getType());
1361 lhs = cir::VecCmpOp::create(builder, loc, resTy, cmpOpKind, lhs, zeroVec);
1362 rhs = cir::VecCmpOp::create(builder, loc, resTy, cmpOpKind, rhs, zeroVec);
1363 mlir::Value vecOr = builder.createOr(loc, lhs, rhs);
1364 return builder.createIntCast(vecOr, resTy);
1365 }
1366
1368 mlir::Type resTy = cgf.convertType(e->getType());
1369 mlir::Location loc = cgf.getLoc(e->getExprLoc());
1370
1371 CIRGenFunction::ConditionalEvaluation eval(cgf);
1372
1373 mlir::Value lhsCondV = cgf.evaluateExprAsBool(e->getLHS());
1374 auto resOp = cir::TernaryOp::create(
1375 builder, loc, lhsCondV, /*trueBuilder=*/
1376 [&](mlir::OpBuilder &b, mlir::Location loc) {
1377 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1378 b.getInsertionBlock()};
1379 cgf.curLexScope->setAsTernary();
1380 auto res = cir::ConstantOp::create(b, loc, builder.getTrueAttr());
1381 cir::YieldOp::create(b, loc, res.getRes());
1382 },
1383 /*falseBuilder*/
1384 [&](mlir::OpBuilder &b, mlir::Location loc) {
1385 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1386 b.getInsertionBlock()};
1387 cgf.curLexScope->setAsTernary();
1388 mlir::Value res = cgf.evaluateExprAsBool(e->getRHS());
1389 lexScope.forceCleanup({&res});
1390 cir::YieldOp::create(b, loc, res);
1391 });
1392
1393 return maybePromoteBoolResult(resOp.getResult(), resTy);
1394 }
1395
1396 mlir::Value VisitBinPtrMemD(const BinaryOperator *e) {
1397 return emitLoadOfLValue(e);
1398 }
1399
1400 mlir::Value VisitBinPtrMemI(const BinaryOperator *e) {
1401 return emitLoadOfLValue(e);
1402 }
1403
1404 // Other Operators.
1405 mlir::Value VisitBlockExpr(const BlockExpr *e) {
1406 cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: block");
1407 return {};
1408 }
1409
1410 mlir::Value VisitChooseExpr(ChooseExpr *e) {
1411 return Visit(e->getChosenSubExpr());
1412 }
1413
1414 mlir::Value VisitObjCStringLiteral(const ObjCStringLiteral *e) {
1415 cgf.cgm.errorNYI(e->getSourceRange(),
1416 "ScalarExprEmitter: objc string literal");
1417 return {};
1418 }
1419 mlir::Value VisitObjCBoxedExpr(ObjCBoxedExpr *e) {
1420 cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: objc boxed");
1421 return {};
1422 }
1423 mlir::Value VisitObjCArrayLiteral(ObjCArrayLiteral *e) {
1424 cgf.cgm.errorNYI(e->getSourceRange(),
1425 "ScalarExprEmitter: objc array literal");
1426 return {};
1427 }
1428 mlir::Value VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *e) {
1429 cgf.cgm.errorNYI(e->getSourceRange(),
1430 "ScalarExprEmitter: objc dictionary literal");
1431 return {};
1432 }
1433
1434 mlir::Value convertVec3AndVec4(CIRGenBuilderTy &builder, mlir::Location loc,
1435 mlir::Value src, unsigned numElementsDst) {
1436 static constexpr int64_t mask[] = {0, 1, 2, -1};
1437 return builder.createVecShuffle(
1438 loc, src, llvm::ArrayRef<int64_t>(mask, numElementsDst));
1439 }
1440
1441 // Create cast instructions for converting MLIR value \p Src to MLIR type \p
1442 // DstTy. \p Src has the same size as \p DstTy. Both are single value types
1443 // but could be scalar or vectors of different lengths, and either can be
1444 // pointer.
1445 //
1446 // There are 4 cases:
1447 // 1. non-pointer -> non-pointer : needs 1 bitcast
1448 // 2. pointer -> pointer : needs 1 bitcast or addrspacecast
1449 // 3. pointer -> non-pointer
1450 // a) pointer -> intptr_t : needs 1 ptrtoint
1451 // b) pointer -> non-intptr_t : needs 1 ptrtoint then 1 bitcast
1452 // 4. non-pointer -> pointer
1453 // a) intptr_t -> pointer : needs 1 inttoptr
1454 // b) non-intptr_t -> pointer : needs 1 bitcast then 1 inttoptr
1455 //
1456 // Note: for cases 3b and 4b two casts are required since LLVM casts do not
1457 // allow casting directly between pointer types and non-integer non-pointer
1458 // types.
1459 mlir::Value createCastsForTypeOfSameSize(mlir::Value src, mlir::Type dstTy) {
1460 mlir::Type srcTy = src.getType();
1461
1462 // Case 1.
1463 if (!isa<cir::PointerType>(srcTy) && !isa<cir::PointerType>(dstTy))
1464 return builder.createBitcast(src, dstTy);
1465
1466 // Case 2.
1467 if (isa<cir::PointerType>(srcTy) && isa<cir::PointerType>(dstTy)) {
1468 cgf.cgm.errorNYI(
1469 "ScalarExprEmitter: createCastsForTypeOfSameSize Case 2");
1470 return {};
1471 }
1472
1473 // Case 3.
1474 if (isa<cir::PointerType>(srcTy) && !isa<cir::PointerType>(dstTy)) {
1475 if (!isa<cir::IntType>(dstTy)) {
1476 cgf.cgm.errorNYI(
1477 "ScalarExprEmitter: createCastsForTypeOfSameSize Case 3a");
1478 }
1479
1480 cgf.cgm.errorNYI(
1481 "ScalarExprEmitter: createCastsForTypeOfSameSize Case 3a and 3b");
1482 return {};
1483 }
1484
1485 // Case 4b.
1486 if (!isa<cir::IntType>(srcTy)) {
1487 cgf.cgm.errorNYI(
1488 "ScalarExprEmitter: createCastsForTypeOfSameSize Case 4a");
1489 return {};
1490 }
1491 // Cases 4a and 4b.
1492 return builder.createIntToPtr(src, dstTy);
1493 }
1494
1495 mlir::Value VisitAsTypeExpr(AsTypeExpr *e) {
1496 mlir::Value src = cgf.emitScalarExpr(e->getSrcExpr());
1497 mlir::Type srcTy = src.getType();
1498 mlir::Type dstTy = cgf.convertType(e->getType());
1499
1500 unsigned numElementsSrc = isa<cir::VectorType>(srcTy)
1501 ? cast<cir::VectorType>(srcTy).getSize()
1502 : 0;
1503 unsigned numElementsDst = isa<cir::VectorType>(dstTy)
1504 ? cast<cir::VectorType>(dstTy).getSize()
1505 : 0;
1506
1507 // Use bit vector expansion for ext_vector_type boolean vectors.
1508 if (e->getType()->isExtVectorBoolType()) {
1509 cgf.cgm.errorNYI(e->getSourceRange(),
1510 "ScalarExprEmitter: VisitAsTypeExpr ExtVectorBoolType");
1511 return {};
1512 }
1513
1514 // Going from vec3 to non-vec3 is a special case and requires a shuffle
1515 // vector to get a vec4, then a bitcast if the target type is different.
1516 if (numElementsSrc == 3 && numElementsDst != 3) {
1517 cgf.cgm.errorNYI(e->getSourceRange(),
1518 "ScalarExprEmitter: VisitAsTypeExpr numElemsSrc = 3, "
1519 "numElemsDst != 3");
1520 return {};
1521 }
1522
1523 // Going from non-vec3 to vec3 is a special case and requires a bitcast
1524 // to vec4 if the original type is not vec4, then a shuffle vector to
1525 // get a vec3.
1526 if (numElementsSrc != 3 && numElementsDst == 3) {
1527 mlir::Location loc = cgf.getLoc(e->getExprLoc());
1528 auto dstElemTy = cast<cir::VectorType>(dstTy).getElementType();
1529 auto dstVec4Ty = cir::VectorType::get(dstElemTy, 4);
1530 src = createCastsForTypeOfSameSize(src, dstVec4Ty);
1531 src = convertVec3AndVec4(builder, loc, src, 3);
1532 return src;
1533 }
1534
1535 return createCastsForTypeOfSameSize(src, dstTy);
1536 }
1537
1538 mlir::Value VisitAtomicExpr(AtomicExpr *e) {
1539 return cgf.emitAtomicExpr(e).getValue();
1540 }
1541};
1542
1543LValue ScalarExprEmitter::emitCompoundAssignLValue(
1544 const CompoundAssignOperator *e,
1545 mlir::Value (ScalarExprEmitter::*func)(const BinOpInfo &),
1546 mlir::Value &result) {
1548 return cgf.emitScalarCompoundAssignWithComplex(e, result);
1549
1550 QualType lhsTy = e->getLHS()->getType();
1551 BinOpInfo opInfo;
1552
1553 // Emit the RHS first. __block variables need to have the rhs evaluated
1554 // first, plus this should improve codegen a little.
1555
1556 QualType promotionTypeCR = getPromotionType(e->getComputationResultType());
1557 if (promotionTypeCR.isNull())
1558 promotionTypeCR = e->getComputationResultType();
1559
1560 QualType promotionTypeLHS = getPromotionType(e->getComputationLHSType());
1561 QualType promotionTypeRHS = getPromotionType(e->getRHS()->getType());
1562
1563 if (!promotionTypeRHS.isNull())
1564 opInfo.rhs = cgf.emitPromotedScalarExpr(e->getRHS(), promotionTypeRHS);
1565 else
1566 opInfo.rhs = Visit(e->getRHS());
1567
1568 opInfo.fullType = promotionTypeCR;
1569 opInfo.compType = opInfo.fullType;
1570 if (const auto *vecType = opInfo.fullType->getAs<VectorType>())
1571 opInfo.compType = vecType->getElementType();
1572 opInfo.opcode = e->getOpcode();
1573 opInfo.fpFeatures = e->getFPFeaturesInEffect(cgf.getLangOpts());
1574 opInfo.e = e;
1575 opInfo.loc = e->getSourceRange();
1576
1577 // Load/convert the LHS
1578 LValue lhsLV = cgf.emitLValue(e->getLHS());
1579
1580 if (lhsTy->getAs<AtomicType>()) {
1581 cgf.cgm.errorNYI(result.getLoc(), "atomic lvalue assign");
1582 return LValue();
1583 }
1584
1585 opInfo.lhs = emitLoadOfLValue(lhsLV, e->getExprLoc());
1586
1587 CIRGenFunction::SourceLocRAIIObject sourceloc{
1588 cgf, cgf.getLoc(e->getSourceRange())};
1589 SourceLocation loc = e->getExprLoc();
1590 if (!promotionTypeLHS.isNull())
1591 opInfo.lhs = emitScalarConversion(opInfo.lhs, lhsTy, promotionTypeLHS, loc);
1592 else
1593 opInfo.lhs = emitScalarConversion(opInfo.lhs, lhsTy,
1594 e->getComputationLHSType(), loc);
1595
1596 // Expand the binary operator.
1597 result = (this->*func)(opInfo);
1598
1599 // Convert the result back to the LHS type,
1600 // potentially with Implicit Conversion sanitizer check.
1601 result = emitScalarConversion(result, promotionTypeCR, lhsTy, loc,
1602 ScalarConversionOpts(cgf.sanOpts));
1603
1604 // Store the result value into the LHS lvalue. Bit-fields are handled
1605 // specially because the result is altered by the store, i.e., [C99 6.5.16p1]
1606 // 'An assignment expression has the value of the left operand after the
1607 // assignment...'.
1608 if (lhsLV.isBitField())
1609 cgf.emitStoreThroughBitfieldLValue(RValue::get(result), lhsLV);
1610 else
1611 cgf.emitStoreThroughLValue(RValue::get(result), lhsLV);
1612
1613 if (cgf.getLangOpts().OpenMP)
1614 cgf.cgm.errorNYI(e->getSourceRange(), "openmp");
1615
1616 return lhsLV;
1617}
1618
1619mlir::Value ScalarExprEmitter::emitComplexToScalarConversion(mlir::Location lov,
1620 mlir::Value value,
1621 CastKind kind,
1622 QualType destTy) {
1623 cir::CastKind castOpKind;
1624 switch (kind) {
1625 case CK_FloatingComplexToReal:
1626 castOpKind = cir::CastKind::float_complex_to_real;
1627 break;
1628 case CK_IntegralComplexToReal:
1629 castOpKind = cir::CastKind::int_complex_to_real;
1630 break;
1631 case CK_FloatingComplexToBoolean:
1632 castOpKind = cir::CastKind::float_complex_to_bool;
1633 break;
1634 case CK_IntegralComplexToBoolean:
1635 castOpKind = cir::CastKind::int_complex_to_bool;
1636 break;
1637 default:
1638 llvm_unreachable("invalid complex-to-scalar cast kind");
1639 }
1640
1641 return builder.createCast(lov, castOpKind, value, cgf.convertType(destTy));
1642}
1643
1644mlir::Value ScalarExprEmitter::emitPromoted(const Expr *e,
1645 QualType promotionType) {
1646 e = e->IgnoreParens();
1647 if (const auto *bo = dyn_cast<BinaryOperator>(e)) {
1648 switch (bo->getOpcode()) {
1649#define HANDLE_BINOP(OP) \
1650 case BO_##OP: \
1651 return emit##OP(emitBinOps(bo, promotionType));
1652 HANDLE_BINOP(Add)
1653 HANDLE_BINOP(Sub)
1654 HANDLE_BINOP(Mul)
1655 HANDLE_BINOP(Div)
1656#undef HANDLE_BINOP
1657 default:
1658 break;
1659 }
1660 } else if (const auto *uo = dyn_cast<UnaryOperator>(e)) {
1661 switch (uo->getOpcode()) {
1662 case UO_Imag:
1663 case UO_Real:
1664 return VisitRealImag(uo, promotionType);
1665 case UO_Minus:
1666 return VisitUnaryMinus(uo, promotionType);
1667 case UO_Plus:
1668 return VisitUnaryPlus(uo, promotionType);
1669 default:
1670 break;
1671 }
1672 }
1673 mlir::Value result = Visit(const_cast<Expr *>(e));
1674 if (result) {
1675 if (!promotionType.isNull())
1676 return emitPromotedValue(result, promotionType);
1677 return emitUnPromotedValue(result, e->getType());
1678 }
1679 return result;
1680}
1681
1682mlir::Value ScalarExprEmitter::emitCompoundAssign(
1683 const CompoundAssignOperator *e,
1684 mlir::Value (ScalarExprEmitter::*func)(const BinOpInfo &)) {
1685
1686 bool ignore = std::exchange(ignoreResultAssign, false);
1687 mlir::Value rhs;
1688 LValue lhs = emitCompoundAssignLValue(e, func, rhs);
1689
1690 // If the result is clearly ignored, return now.
1691 if (ignore)
1692 return {};
1693
1694 // The result of an assignment in C is the assigned r-value.
1695 if (!cgf.getLangOpts().CPlusPlus)
1696 return rhs;
1697
1698 // If the lvalue is non-volatile, return the computed value of the assignment.
1699 if (!lhs.isVolatile())
1700 return rhs;
1701
1702 // Otherwise, reload the value.
1703 return emitLoadOfLValue(lhs, e->getExprLoc());
1704}
1705
1706mlir::Value ScalarExprEmitter::VisitExprWithCleanups(ExprWithCleanups *e) {
1707 CIRGenFunction::FullExprCleanupScope scope(cgf, e->getSubExpr());
1708 mlir::Value v = Visit(e->getSubExpr());
1709 // Defend against dominance problems caused by jumps out of expression
1710 // evaluation through the shared cleanup block.
1711 scope.exit({&v});
1712 return v;
1713}
1714
1715} // namespace
1716
1717LValue
1719 ScalarExprEmitter emitter(*this, builder);
1720 mlir::Value result;
1721 switch (e->getOpcode()) {
1722#define COMPOUND_OP(Op) \
1723 case BO_##Op##Assign: \
1724 return emitter.emitCompoundAssignLValue(e, &ScalarExprEmitter::emit##Op, \
1725 result)
1726 COMPOUND_OP(Mul);
1727 COMPOUND_OP(Div);
1728 COMPOUND_OP(Rem);
1729 COMPOUND_OP(Add);
1730 COMPOUND_OP(Sub);
1731 COMPOUND_OP(Shl);
1732 COMPOUND_OP(Shr);
1734 COMPOUND_OP(Xor);
1735 COMPOUND_OP(Or);
1736#undef COMPOUND_OP
1737
1738 case BO_PtrMemD:
1739 case BO_PtrMemI:
1740 case BO_Mul:
1741 case BO_Div:
1742 case BO_Rem:
1743 case BO_Add:
1744 case BO_Sub:
1745 case BO_Shl:
1746 case BO_Shr:
1747 case BO_LT:
1748 case BO_GT:
1749 case BO_LE:
1750 case BO_GE:
1751 case BO_EQ:
1752 case BO_NE:
1753 case BO_Cmp:
1754 case BO_And:
1755 case BO_Xor:
1756 case BO_Or:
1757 case BO_LAnd:
1758 case BO_LOr:
1759 case BO_Assign:
1760 case BO_Comma:
1761 llvm_unreachable("Not valid compound assignment operators");
1762 }
1763 llvm_unreachable("Unhandled compound assignment operator");
1764}
1765
1766/// Emit the computation of the specified expression of scalar type.
1768 bool ignoreResultAssign) {
1769 assert(e && hasScalarEvaluationKind(e->getType()) &&
1770 "Invalid scalar expression to emit");
1771
1772 return ScalarExprEmitter(*this, builder, ignoreResultAssign)
1773 .Visit(const_cast<Expr *>(e));
1774}
1775
1777 QualType promotionType) {
1778 if (!promotionType.isNull())
1779 return ScalarExprEmitter(*this, builder).emitPromoted(e, promotionType);
1780 return ScalarExprEmitter(*this, builder).Visit(const_cast<Expr *>(e));
1781}
1782
1783[[maybe_unused]] static bool mustVisitNullValue(const Expr *e) {
1784 // If a null pointer expression's type is the C++0x nullptr_t and
1785 // the expression is not a simple literal, it must be evaluated
1786 // for its potential side effects.
1788 return false;
1789 return e->getType()->isNullPtrType();
1790}
1791
1792/// If \p e is a widened promoted integer, get its base (unpromoted) type.
1793static std::optional<QualType>
1794getUnwidenedIntegerType(const ASTContext &astContext, const Expr *e) {
1795 const Expr *base = e->IgnoreImpCasts();
1796 if (e == base)
1797 return std::nullopt;
1798
1799 QualType baseTy = base->getType();
1800 if (!astContext.isPromotableIntegerType(baseTy) ||
1801 astContext.getTypeSize(baseTy) >= astContext.getTypeSize(e->getType()))
1802 return std::nullopt;
1803
1804 return baseTy;
1805}
1806
1807/// Check if \p e is a widened promoted integer.
1808[[maybe_unused]] static bool isWidenedIntegerOp(const ASTContext &astContext,
1809 const Expr *e) {
1810 return getUnwidenedIntegerType(astContext, e).has_value();
1811}
1812
1813/// Check if we can skip the overflow check for \p Op.
1814[[maybe_unused]] static bool canElideOverflowCheck(const ASTContext &astContext,
1815 const BinOpInfo &op) {
1816 assert((isa<UnaryOperator>(op.e) || isa<BinaryOperator>(op.e)) &&
1817 "Expected a unary or binary operator");
1818
1819 // If the binop has constant inputs and we can prove there is no overflow,
1820 // we can elide the overflow check.
1821 if (!op.mayHaveIntegerOverflow())
1822 return true;
1823
1824 // If a unary op has a widened operand, the op cannot overflow.
1825 if (const auto *uo = dyn_cast<UnaryOperator>(op.e))
1826 return !uo->canOverflow();
1827
1828 // We usually don't need overflow checks for binops with widened operands.
1829 // Multiplication with promoted unsigned operands is a special case.
1830 const auto *bo = cast<BinaryOperator>(op.e);
1831 std::optional<QualType> optionalLHSTy =
1832 getUnwidenedIntegerType(astContext, bo->getLHS());
1833 if (!optionalLHSTy)
1834 return false;
1835
1836 std::optional<QualType> optionalRHSTy =
1837 getUnwidenedIntegerType(astContext, bo->getRHS());
1838 if (!optionalRHSTy)
1839 return false;
1840
1841 QualType lhsTy = *optionalLHSTy;
1842 QualType rhsTy = *optionalRHSTy;
1843
1844 // This is the simple case: binops without unsigned multiplication, and with
1845 // widened operands. No overflow check is needed here.
1846 if ((op.opcode != BO_Mul && op.opcode != BO_MulAssign) ||
1847 !lhsTy->isUnsignedIntegerType() || !rhsTy->isUnsignedIntegerType())
1848 return true;
1849
1850 // For unsigned multiplication the overflow check can be elided if either one
1851 // of the unpromoted types are less than half the size of the promoted type.
1852 unsigned promotedSize = astContext.getTypeSize(op.e->getType());
1853 return (2 * astContext.getTypeSize(lhsTy)) < promotedSize ||
1854 (2 * astContext.getTypeSize(rhsTy)) < promotedSize;
1855}
1856
1857/// Emit pointer + index arithmetic.
1859 const BinOpInfo &op,
1860 bool isSubtraction) {
1861 // Must have binary (not unary) expr here. Unary pointer
1862 // increment/decrement doesn't use this path.
1864
1865 mlir::Value pointer = op.lhs;
1866 Expr *pointerOperand = expr->getLHS();
1867 mlir::Value index = op.rhs;
1868 Expr *indexOperand = expr->getRHS();
1869
1870 // In the case of subtraction, the FE has ensured that the LHS is always the
1871 // pointer. However, addition can have the pointer on either side. We will
1872 // always have a pointer operand and an integer operand, so if the LHS wasn't
1873 // a pointer, we need to swap our values.
1874 if (!isSubtraction && !mlir::isa<cir::PointerType>(pointer.getType())) {
1875 std::swap(pointer, index);
1876 std::swap(pointerOperand, indexOperand);
1877 }
1878 assert(mlir::isa<cir::PointerType>(pointer.getType()) &&
1879 "Need a pointer operand");
1880 assert(mlir::isa<cir::IntType>(index.getType()) && "Need an integer operand");
1881
1882 // Some versions of glibc and gcc use idioms (particularly in their malloc
1883 // routines) that add a pointer-sized integer (known to be a pointer value)
1884 // to a null pointer in order to cast the value back to an integer or as
1885 // part of a pointer alignment algorithm. This is undefined behavior, but
1886 // we'd like to be able to compile programs that use it.
1887 //
1888 // Normally, we'd generate a GEP with a null-pointer base here in response
1889 // to that code, but it's also UB to dereference a pointer created that
1890 // way. Instead (as an acknowledged hack to tolerate the idiom) we will
1891 // generate a direct cast of the integer value to a pointer.
1892 //
1893 // The idiom (p = nullptr + N) is not met if any of the following are true:
1894 //
1895 // The operation is subtraction.
1896 // The index is not pointer-sized.
1897 // The pointer type is not byte-sized.
1898 //
1900 cgf.getContext(), op.opcode, expr->getLHS(), expr->getRHS()))
1901 return cgf.getBuilder().createIntToPtr(index, pointer.getType());
1902
1903 // Differently from LLVM codegen, ABI bits for index sizes is handled during
1904 // LLVM lowering.
1905
1906 // If this is subtraction, negate the index.
1907 if (isSubtraction)
1908 index = cgf.getBuilder().createNeg(cgf.getLoc(op.e->getExprLoc()), index);
1909
1911
1912 const PointerType *pointerType =
1913 pointerOperand->getType()->getAs<PointerType>();
1914 if (!pointerType) {
1915 cgf.cgm.errorNYI("Objective-C:pointer arithmetic with non-pointer type");
1916 return nullptr;
1917 }
1918
1919 QualType elementType = pointerType->getPointeeType();
1920 if (const VariableArrayType *vla =
1921 cgf.getContext().getAsVariableArrayType(elementType)) {
1922 mlir::Value numElements = cgf.getVLASize(vla).numElts;
1923 mlir::Location loc = cgf.getLoc(op.e->getExprLoc());
1924 index = cgf.getBuilder().createCast(cir::CastKind::integral, index,
1925 numElements.getType());
1926 // GEP indexes are signed, and scaling an index isn't permitted to
1927 // signed-overflow, so we use the same semantics for our explicit
1928 // multiply. We suppress this if overflow is not undefined behavior.
1929 cir::OverflowBehavior overflowBehavior =
1930 cgf.getLangOpts().PointerOverflowDefined
1933 index =
1934 cgf.getBuilder().createMul(loc, index, numElements, overflowBehavior);
1936 return cir::PtrStrideOp::create(cgf.getBuilder(), loc, pointer.getType(),
1937 pointer, index);
1938 }
1939
1941 return cir::PtrStrideOp::create(cgf.getBuilder(),
1942 cgf.getLoc(op.e->getExprLoc()),
1943 pointer.getType(), pointer, index);
1944}
1945
1946static bool isIntegerVectorBinOp(mlir::Type ty) {
1947 auto vecTy = mlir::dyn_cast<cir::VectorType>(ty);
1948 return vecTy && mlir::isa<cir::IntType>(vecTy.getElementType());
1949}
1950
1951// Construct a cir.fmuladd op to represent a fused mul-add of `mulOp` and
1952// `addend`. Use negMul and negAdd to negate the first operand of the mul or
1953// the addend respectively. This allows fmuladd to represent a*b-c, or c-a*b.
1954// Patterns in LLVM should catch the negated forms and translate them to
1955// efficient operations.
1956static mlir::Value buildFMulAdd(mlir::Location addLoc, cir::FMulOp mulOp,
1957 mlir::Value addend, CIRGenBuilderTy &builder,
1958 bool negMul, bool negAdd) {
1959 mlir::Location loc = builder.getFusedLoc({mulOp.getLoc(), addLoc});
1960 mlir::Value mulOp0 = mulOp.getLhs();
1961 mlir::Value mulOp1 = mulOp.getRhs();
1962 if (negMul)
1963 mulOp0 = builder.createFNeg(loc, mulOp0);
1964 if (negAdd)
1965 addend = builder.createFNeg(loc, addend);
1966
1967 // Carry the mul's fenv attribute so a constrained fmul yields a constrained
1968 // fmuladd; the builder is under the add's FP options, not the mul's.
1969 mlir::Value fmuladd =
1970 cir::FMulAddOp::create(builder, loc, addend.getType(), mulOp0, mulOp1,
1971 addend, mulOp.getFenvAttr());
1972 mulOp.erase();
1973 return fmuladd;
1974}
1975
1976// Check whether it would be legal to emit a cir.fmuladd op to represent op
1977// and if so, build it.
1978//
1979// Checks that (a) the operation is fusable, and (b) -ffp-contract=on.
1980// Does NOT check the type of the operation - it's assumed that this function
1981// will be called from contexts where it's known that the type is contractable.
1982static mlir::Value tryEmitFMulAdd(mlir::Location loc, const BinOpInfo &op,
1983 CIRGenBuilderTy &builder,
1984 bool isSub = false) {
1985 assert((op.opcode == BO_Add || op.opcode == BO_AddAssign ||
1986 op.opcode == BO_Sub || op.opcode == BO_SubAssign) &&
1987 "Only fadd/fsub can be the root of an fmuladd.");
1988
1989 // Check whether this op is fusable, i.e. -ffp-contract=on. -ffp-contract=fast
1990 // needs fast-math flags on the fmul/fadd, which CIR does not model yet, so it
1991 // fuses nowhere for now.
1993 if (!op.fpFeatures.allowFPContractWithinStatement())
1994 return nullptr;
1995
1996 mlir::Value lhs = op.lhs;
1997 mlir::Value rhs = op.rhs;
1998
1999 // Peek through fneg to look for fmul. Make sure the fneg has no other users,
2000 // and that it is the only use of its operand.
2001 bool negLHS = false;
2002 if (auto lhsNeg = lhs.getDefiningOp<cir::FNegOp>()) {
2003 if (lhsNeg.getResult().use_empty() && lhsNeg.getInput().hasOneUse()) {
2004 lhs = lhsNeg.getInput();
2005 negLHS = true;
2006 }
2007 }
2008
2009 bool negRHS = false;
2010 if (auto rhsNeg = rhs.getDefiningOp<cir::FNegOp>()) {
2011 if (rhsNeg.getResult().use_empty() && rhsNeg.getInput().hasOneUse()) {
2012 rhs = rhsNeg.getInput();
2013 negRHS = true;
2014 }
2015 }
2016
2017 // We have a potentially fusable op. Look for a mul on one of the operands.
2018 // Also make sure that the mul result isn't used directly. In that case,
2019 // there's no point creating a muladd operation.
2020 if (auto lhsMul = lhs.getDefiningOp<cir::FMulOp>()) {
2021 if (lhsMul.getResult().use_empty() || negLHS) {
2022 // If we looked through fneg, erase it.
2023 if (negLHS)
2024 op.lhs.getDefiningOp<cir::FNegOp>().erase();
2025 return buildFMulAdd(loc, lhsMul, op.rhs, builder, negLHS, isSub);
2026 }
2027 }
2028 if (auto rhsMul = rhs.getDefiningOp<cir::FMulOp>()) {
2029 if (rhsMul.getResult().use_empty() || negRHS) {
2030 // If we looked through fneg, erase it.
2031 if (negRHS)
2032 op.rhs.getDefiningOp<cir::FNegOp>().erase();
2033 return buildFMulAdd(loc, rhsMul, op.lhs, builder, isSub ^ negRHS, false);
2034 }
2035 }
2036
2037 return nullptr;
2038}
2039
2040mlir::Value ScalarExprEmitter::emitMul(const BinOpInfo &ops) {
2041 const mlir::Location loc = cgf.getLoc(ops.loc);
2042 if (!isIntegerVectorBinOp(ops.lhs.getType()) &&
2043 ops.compType->isSignedIntegerOrEnumerationType()) {
2044 switch (cgf.getLangOpts().getSignedOverflowBehavior()) {
2045 case LangOptions::SOB_Defined:
2046 if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))
2047 return builder.createMul(loc, ops.lhs, ops.rhs);
2048 [[fallthrough]];
2049 case LangOptions::SOB_Undefined:
2050 if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))
2051 return builder.createNSWMul(loc, ops.lhs, ops.rhs);
2052 [[fallthrough]];
2053 case LangOptions::SOB_Trapping:
2054 if (canElideOverflowCheck(cgf.getContext(), ops))
2055 return builder.createNSWMul(loc, ops.lhs, ops.rhs);
2056 cgf.cgm.errorNYI("sanitizers");
2057 }
2058 }
2059 if (ops.fullType->isConstantMatrixType()) {
2061 cgf.cgm.errorNYI("matrix types");
2062 return nullptr;
2063 }
2064 if (ops.compType->isUnsignedIntegerType() &&
2065 cgf.sanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
2066 !canElideOverflowCheck(cgf.getContext(), ops))
2067 cgf.cgm.errorNYI("unsigned int overflow sanitizer");
2068
2069 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
2070 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, ops.fpFeatures);
2071 return builder.createFMul(loc, ops.lhs, ops.rhs);
2072 }
2073
2074 if (ops.isFixedPointOp()) {
2076 cgf.cgm.errorNYI("fixed point");
2077 return nullptr;
2078 }
2079
2080 return cir::MulOp::create(builder, cgf.getLoc(ops.loc),
2081 cgf.convertType(ops.fullType), ops.lhs, ops.rhs);
2082}
2083mlir::Value ScalarExprEmitter::emitDiv(const BinOpInfo &ops) {
2084 const mlir::Location loc = cgf.getLoc(ops.loc);
2085 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
2086 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, ops.fpFeatures);
2087 return builder.createFDiv(loc, ops.lhs, ops.rhs);
2088 }
2089 return cir::DivOp::create(builder, loc, cgf.convertType(ops.fullType),
2090 ops.lhs, ops.rhs);
2091}
2092mlir::Value ScalarExprEmitter::emitRem(const BinOpInfo &ops) {
2093 const mlir::Location loc = cgf.getLoc(ops.loc);
2094 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
2095 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, ops.fpFeatures);
2096 return builder.createFRem(loc, ops.lhs, ops.rhs);
2097 }
2098 return cir::RemOp::create(builder, loc, cgf.convertType(ops.fullType),
2099 ops.lhs, ops.rhs);
2100}
2101
2102mlir::Value ScalarExprEmitter::emitAdd(const BinOpInfo &ops) {
2103 if (mlir::isa<cir::PointerType>(ops.lhs.getType()) ||
2104 mlir::isa<cir::PointerType>(ops.rhs.getType()))
2105 return emitPointerArithmetic(cgf, ops, /*isSubtraction=*/
2106 false);
2107
2108 const mlir::Location loc = cgf.getLoc(ops.loc);
2109 if (!isIntegerVectorBinOp(ops.lhs.getType()) &&
2110 ops.compType->isSignedIntegerOrEnumerationType()) {
2111 switch (cgf.getLangOpts().getSignedOverflowBehavior()) {
2112 case LangOptions::SOB_Defined:
2113 if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))
2114 return builder.createAdd(loc, ops.lhs, ops.rhs);
2115 [[fallthrough]];
2116 case LangOptions::SOB_Undefined:
2117 if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))
2118 return builder.createNSWAdd(loc, ops.lhs, ops.rhs);
2119 [[fallthrough]];
2120 case LangOptions::SOB_Trapping:
2121 if (canElideOverflowCheck(cgf.getContext(), ops))
2122 return builder.createNSWAdd(loc, ops.lhs, ops.rhs);
2123 cgf.cgm.errorNYI("sanitizers");
2124 }
2125 }
2126 if (ops.fullType->isConstantMatrixType()) {
2128 cgf.cgm.errorNYI("matrix types");
2129 return nullptr;
2130 }
2131
2132 if (ops.compType->isUnsignedIntegerType() &&
2133 cgf.sanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
2134 !canElideOverflowCheck(cgf.getContext(), ops))
2135 cgf.cgm.errorNYI("unsigned int overflow sanitizer");
2136
2137 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
2138 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, ops.fpFeatures);
2139 // Try to form an fmuladd.
2140 if (mlir::Value fmuladd = tryEmitFMulAdd(loc, ops, builder))
2141 return fmuladd;
2142 return builder.createFAdd(loc, ops.lhs, ops.rhs);
2143 }
2144
2145 if (ops.isFixedPointOp()) {
2147 cgf.cgm.errorNYI("fixed point");
2148 return {};
2149 }
2150
2151 return builder.createAdd(loc, ops.lhs, ops.rhs);
2152}
2153
2154mlir::Value ScalarExprEmitter::emitSub(const BinOpInfo &ops) {
2155 const mlir::Location loc = cgf.getLoc(ops.loc);
2156 // The LHS is always a pointer if either side is.
2157 if (!mlir::isa<cir::PointerType>(ops.lhs.getType())) {
2158 if (!isIntegerVectorBinOp(ops.lhs.getType()) &&
2159 ops.compType->isSignedIntegerOrEnumerationType()) {
2160 switch (cgf.getLangOpts().getSignedOverflowBehavior()) {
2161 case LangOptions::SOB_Defined: {
2162 if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))
2163 return builder.createSub(loc, ops.lhs, ops.rhs);
2164 [[fallthrough]];
2165 }
2166 case LangOptions::SOB_Undefined:
2167 if (!cgf.sanOpts.has(SanitizerKind::SignedIntegerOverflow))
2168 return builder.createNSWSub(loc, ops.lhs, ops.rhs);
2169 [[fallthrough]];
2170 case LangOptions::SOB_Trapping:
2171 if (canElideOverflowCheck(cgf.getContext(), ops))
2172 return builder.createNSWSub(loc, ops.lhs, ops.rhs);
2173 cgf.cgm.errorNYI("sanitizers");
2174 }
2175 }
2176
2177 if (ops.fullType->isConstantMatrixType()) {
2179 cgf.cgm.errorNYI("matrix types");
2180 return nullptr;
2181 }
2182
2183 if (ops.compType->isUnsignedIntegerType() &&
2184 cgf.sanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
2185 !canElideOverflowCheck(cgf.getContext(), ops))
2186 cgf.cgm.errorNYI("unsigned int overflow sanitizer");
2187
2188 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
2189 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, ops.fpFeatures);
2190 // Try to form an fmuladd.
2191 if (mlir::Value fmuladd =
2192 tryEmitFMulAdd(loc, ops, builder, /*isSub=*/true))
2193 return fmuladd;
2194 return builder.createFSub(loc, ops.lhs, ops.rhs);
2195 }
2196
2197 if (ops.isFixedPointOp()) {
2199 cgf.cgm.errorNYI("fixed point");
2200 return {};
2201 }
2202
2203 return builder.createSub(loc, ops.lhs, ops.rhs);
2204 }
2205
2206 // If the RHS is not a pointer, then we have normal pointer
2207 // arithmetic.
2208 if (!mlir::isa<cir::PointerType>(ops.rhs.getType()))
2209 return emitPointerArithmetic(cgf, ops, /*isSubtraction=*/true);
2210
2211 // Otherwise, this is a pointer subtraction
2212
2213 // Do the raw subtraction part.
2214 //
2215 // TODO(cir): note for LLVM lowering out of this; when expanding this into
2216 // LLVM we shall take VLA's, division by element size, etc.
2217 //
2218 // See more in `EmitSub` in CGExprScalar.cpp.
2220 return cir::PtrDiffOp::create(builder, cgf.getLoc(ops.loc), cgf.ptrDiffTy,
2221 ops.lhs, ops.rhs);
2222}
2223
2224mlir::Value ScalarExprEmitter::emitShl(const BinOpInfo &ops) {
2225 // TODO: This misses out on the sanitizer check below.
2226 if (ops.isFixedPointOp()) {
2228 cgf.cgm.errorNYI("fixed point");
2229 return {};
2230 }
2231
2232 // CIR accepts shift between different types, meaning nothing special
2233 // to be done here. OTOH, LLVM requires the LHS and RHS to be the same type:
2234 // promote or truncate the RHS to the same size as the LHS.
2235
2236 bool sanitizeSignedBase = cgf.sanOpts.has(SanitizerKind::ShiftBase) &&
2237 ops.compType->hasSignedIntegerRepresentation() &&
2239 !cgf.getLangOpts().CPlusPlus20;
2240 bool sanitizeUnsignedBase =
2241 cgf.sanOpts.has(SanitizerKind::UnsignedShiftBase) &&
2242 ops.compType->hasUnsignedIntegerRepresentation();
2243 bool sanitizeBase = sanitizeSignedBase || sanitizeUnsignedBase;
2244 bool sanitizeExponent = cgf.sanOpts.has(SanitizerKind::ShiftExponent);
2245
2246 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2247 if (cgf.getLangOpts().OpenCL)
2248 cgf.cgm.errorNYI("opencl");
2249 else if ((sanitizeBase || sanitizeExponent) &&
2250 mlir::isa<cir::IntType>(ops.lhs.getType()))
2251 cgf.cgm.errorNYI("sanitizers");
2252
2253 return builder.createShiftLeft(cgf.getLoc(ops.loc), ops.lhs, ops.rhs);
2254}
2255
2256mlir::Value ScalarExprEmitter::emitShr(const BinOpInfo &ops) {
2257 // TODO: This misses out on the sanitizer check below.
2258 if (ops.isFixedPointOp()) {
2260 cgf.cgm.errorNYI("fixed point");
2261 return {};
2262 }
2263
2264 // CIR accepts shift between different types, meaning nothing special
2265 // to be done here. OTOH, LLVM requires the LHS and RHS to be the same type:
2266 // promote or truncate the RHS to the same size as the LHS.
2267
2268 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2269 if (cgf.getLangOpts().OpenCL)
2270 cgf.cgm.errorNYI("opencl");
2271 else if (cgf.sanOpts.has(SanitizerKind::ShiftExponent) &&
2272 mlir::isa<cir::IntType>(ops.lhs.getType()))
2273 cgf.cgm.errorNYI("sanitizers");
2274
2275 // Note that we don't need to distinguish unsigned treatment at this
2276 // point since it will be handled later by LLVM lowering.
2277 return builder.createShiftRight(cgf.getLoc(ops.loc), ops.lhs, ops.rhs);
2278}
2279
2280mlir::Value ScalarExprEmitter::emitAnd(const BinOpInfo &ops) {
2281 return cir::AndOp::create(builder, cgf.getLoc(ops.loc), ops.lhs, ops.rhs);
2282}
2283mlir::Value ScalarExprEmitter::emitXor(const BinOpInfo &ops) {
2284 return cir::XorOp::create(builder, cgf.getLoc(ops.loc), ops.lhs, ops.rhs);
2285}
2286mlir::Value ScalarExprEmitter::emitOr(const BinOpInfo &ops) {
2287 return cir::OrOp::create(builder, cgf.getLoc(ops.loc), ops.lhs, ops.rhs);
2288}
2289
2290// Emit code for an explicit or implicit cast. Implicit
2291// casts have to handle a more broad range of conversions than explicit
2292// casts, as they handle things like function to ptr-to-function decay
2293// etc.
2294mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
2295 Expr *subExpr = ce->getSubExpr();
2296 QualType destTy = ce->getType();
2297 CastKind kind = ce->getCastKind();
2298 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, ce);
2299
2300 // These cases are generally not written to ignore the result of evaluating
2301 // their sub-expressions, so we clear this now.
2302 ignoreResultAssign = false;
2303
2304 switch (kind) {
2305 case clang::CK_Dependent:
2306 llvm_unreachable("dependent cast kind in CIR gen!");
2307 case clang::CK_BuiltinFnToFnPtr:
2308 llvm_unreachable("builtin functions are handled elsewhere");
2309 case CK_LValueBitCast:
2310 case CK_LValueToRValueBitCast: {
2311 LValue sourceLVal = cgf.emitLValue(subExpr);
2312 Address sourceAddr = sourceLVal.getAddress();
2313
2314 mlir::Type destElemTy = cgf.convertTypeForMem(destTy);
2315 Address destAddr = sourceAddr.withElementType(cgf.getBuilder(), destElemTy);
2316 LValue destLVal = cgf.makeAddrLValue(destAddr, destTy);
2318 return emitLoadOfLValue(destLVal, ce->getExprLoc());
2319 }
2320
2321 case CK_CPointerToObjCPointerCast:
2322 case CK_BlockPointerToObjCPointerCast:
2323 case CK_AnyPointerToBlockPointerCast:
2324 case CK_BitCast: {
2325 mlir::Value src = Visit(const_cast<Expr *>(subExpr));
2326 mlir::Type dstTy = cgf.convertType(destTy);
2327
2329
2330 if (cgf.sanOpts.has(SanitizerKind::CFIUnrelatedCast))
2331 cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
2332 "sanitizer support");
2333
2334 if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)
2335 cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
2336 "strict vtable pointers");
2337
2338 // Update heapallocsite metadata when there is an explicit pointer cast.
2340
2341 // If Src is a fixed vector and Dst is a scalable vector, and both have the
2342 // same element type, use the llvm.vector.insert intrinsic to perform the
2343 // bitcast.
2345
2346 // If Src is a scalable vector and Dst is a fixed vector, and both have the
2347 // same element type, use the llvm.vector.extract intrinsic to perform the
2348 // bitcast.
2350
2351 // Perform VLAT <-> VLST bitcast through memory.
2352 // TODO: since the llvm.experimental.vector.{insert,extract} intrinsics
2353 // require the element types of the vectors to be the same, we
2354 // need to keep this around for bitcasts between VLAT <-> VLST where
2355 // the element types of the vectors are not the same, until we figure
2356 // out a better way of doing these casts.
2358
2359 return cgf.getBuilder().createBitcast(cgf.getLoc(subExpr->getSourceRange()),
2360 src, dstTy);
2361 }
2362 case CK_AddressSpaceConversion: {
2363 Expr::EvalResult result;
2364 if (subExpr->EvaluateAsRValue(result, cgf.getContext()) &&
2365 result.Val.isNullPointer()) {
2366 // If e has side effect, it is emitted even if its final result is a
2367 // null pointer. In that case, a DCE pass should be able to
2368 // eliminate the useless instructions emitted during translating E.
2369 if (result.HasSideEffects)
2370 Visit(subExpr);
2371 return cgf.cgm.emitNullConstant(destTy,
2372 cgf.getLoc(subExpr->getExprLoc()));
2373 }
2374 return cgf.performAddrSpaceCast(Visit(subExpr), convertType(destTy));
2375 }
2376
2377 case CK_AtomicToNonAtomic:
2378 case CK_NonAtomicToAtomic:
2379 case CK_UserDefinedConversion:
2380 return Visit(const_cast<Expr *>(subExpr));
2381 case CK_NoOp:
2382 return ce->changesVolatileQualification() ? emitLoadOfLValue(ce)
2383 : Visit(subExpr);
2384 case CK_IntegralToPointer: {
2385 mlir::Type destCIRTy = cgf.convertType(destTy);
2386 mlir::Value src = Visit(const_cast<Expr *>(subExpr));
2387
2388 // Properly resize by casting to an int of the same size as the pointer.
2389 // Clang's IntegralToPointer includes 'bool' as the source, but in CIR
2390 // 'bool' is not an integral type. So check the source type to get the
2391 // correct CIR conversion.
2392 mlir::Type middleTy = cgf.cgm.getDataLayout().getIntPtrType(destCIRTy);
2393 mlir::Value middleVal = builder.createCast(
2394 subExpr->getType()->isBooleanType() ? cir::CastKind::bool_to_int
2395 : cir::CastKind::integral,
2396 src, middleTy);
2397
2398 if (cgf.cgm.getCodeGenOpts().StrictVTablePointers) {
2399 cgf.cgm.errorNYI(subExpr->getSourceRange(),
2400 "IntegralToPointer: strict vtable pointers");
2401 return {};
2402 }
2403
2404 return builder.createIntToPtr(middleVal, destCIRTy);
2405 }
2406
2407 case CK_BaseToDerived: {
2408 const CXXRecordDecl *derivedClassDecl = destTy->getPointeeCXXRecordDecl();
2409 assert(derivedClassDecl && "BaseToDerived arg isn't a C++ object pointer!");
2410 Address base = cgf.emitPointerWithAlignment(subExpr);
2411 Address derived = cgf.getAddressOfDerivedClass(
2412 cgf.getLoc(ce->getSourceRange()), base, derivedClassDecl, ce->path(),
2414
2415 // C++11 [expr.static.cast]p11: Behavior is undefined if a downcast is
2416 // performed and the object is not of the derived type.
2418
2419 return cgf.getAsNaturalPointerTo(derived, ce->getType()->getPointeeType());
2420 }
2421 case CK_UncheckedDerivedToBase:
2422 case CK_DerivedToBase: {
2423 // The EmitPointerWithAlignment path does this fine; just discard
2424 // the alignment.
2426 ce->getType()->getPointeeType());
2427 }
2428 case CK_Dynamic: {
2429 Address v = cgf.emitPointerWithAlignment(subExpr);
2430 const auto *dce = cast<CXXDynamicCastExpr>(ce);
2431 return cgf.emitDynamicCast(v, dce);
2432 }
2433 case CK_ArrayToPointerDecay:
2434 return cgf.emitArrayToPointerDecay(subExpr).getPointer();
2435
2436 case CK_NullToPointer: {
2437 if (mustVisitNullValue(subExpr))
2438 cgf.emitIgnoredExpr(subExpr);
2439
2440 // Note that DestTy is used as the MLIR type instead of a custom
2441 // nullptr type.
2442 mlir::Type ty = cgf.convertType(destTy);
2443 return builder.getNullPtr(ty, cgf.getLoc(subExpr->getExprLoc()));
2444 }
2445
2446 case CK_NullToMemberPointer: {
2447 if (mustVisitNullValue(subExpr))
2448 cgf.emitIgnoredExpr(subExpr);
2449
2451
2452 const MemberPointerType *mpt = ce->getType()->getAs<MemberPointerType>();
2453 mlir::Location loc = cgf.getLoc(subExpr->getExprLoc());
2454 return cgf.getBuilder().getConstant(
2455 loc, cgf.cgm.emitNullMemberAttr(destTy, mpt));
2456 }
2457
2458 case CK_ReinterpretMemberPointer: {
2459 mlir::Value src = Visit(subExpr);
2460 return builder.createBitcast(cgf.getLoc(subExpr->getExprLoc()), src,
2461 cgf.convertType(destTy));
2462 }
2463 case CK_BaseToDerivedMemberPointer:
2464 case CK_DerivedToBaseMemberPointer: {
2465 mlir::Value src = Visit(subExpr);
2466
2468
2469 QualType derivedTy =
2470 kind == CK_DerivedToBaseMemberPointer ? subExpr->getType() : destTy;
2471 const auto *mpType = derivedTy->castAs<MemberPointerType>();
2472 NestedNameSpecifier qualifier = mpType->getQualifier();
2473 assert(qualifier && "member pointer without class qualifier");
2474 const Type *qualifierType = qualifier.getAsType();
2475 assert(qualifierType && "member pointer qualifier is not a type");
2476 const CXXRecordDecl *derivedClass = qualifierType->getAsCXXRecordDecl();
2477 CharUnits offset =
2478 cgf.cgm.computeNonVirtualBaseClassOffset(derivedClass, ce->path());
2479
2480 mlir::Location loc = cgf.getLoc(subExpr->getExprLoc());
2481 mlir::Type resultTy = cgf.convertType(destTy);
2482 mlir::IntegerAttr offsetAttr = builder.getIndexAttr(offset.getQuantity());
2483
2484 if (subExpr->getType()->isMemberFunctionPointerType()) {
2485 if (kind == CK_BaseToDerivedMemberPointer)
2486 return cir::DerivedMethodOp::create(builder, loc, resultTy, src,
2487 offsetAttr);
2488 return cir::BaseMethodOp::create(builder, loc, resultTy, src, offsetAttr);
2489 }
2490
2491 if (kind == CK_BaseToDerivedMemberPointer)
2492 return cir::DerivedDataMemberOp::create(builder, loc, resultTy, src,
2493 offsetAttr);
2494 return cir::BaseDataMemberOp::create(builder, loc, resultTy, src,
2495 offsetAttr);
2496 }
2497
2498 case CK_LValueToRValue:
2499 assert(cgf.getContext().hasSameUnqualifiedType(subExpr->getType(), destTy));
2500 assert(subExpr->isGLValue() && "lvalue-to-rvalue applied to r-value!");
2501 return Visit(const_cast<Expr *>(subExpr));
2502
2503 case CK_IntegralCast: {
2504 ScalarConversionOpts opts;
2505 if (auto *ice = dyn_cast<ImplicitCastExpr>(ce)) {
2506 if (!ice->isPartOfExplicitCast())
2507 opts = ScalarConversionOpts(cgf.sanOpts);
2508 }
2509 return emitScalarConversion(Visit(subExpr), subExpr->getType(), destTy,
2510 ce->getExprLoc(), opts);
2511 }
2512
2513 case CK_FloatingComplexToReal:
2514 case CK_IntegralComplexToReal:
2515 case CK_FloatingComplexToBoolean:
2516 case CK_IntegralComplexToBoolean: {
2517 mlir::Value value = cgf.emitComplexExpr(subExpr);
2518 return emitComplexToScalarConversion(cgf.getLoc(ce->getExprLoc()), value,
2519 kind, destTy);
2520 }
2521
2522 case CK_FloatingRealToComplex:
2523 case CK_FloatingComplexCast:
2524 case CK_IntegralRealToComplex:
2525 case CK_IntegralComplexCast:
2526 case CK_IntegralComplexToFloatingComplex:
2527 case CK_FloatingComplexToIntegralComplex:
2528 llvm_unreachable("scalar cast to non-scalar value");
2529
2530 case CK_PointerToIntegral: {
2531 assert(!destTy->isBooleanType() && "bool should use PointerToBool");
2532 if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)
2533 cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
2534 "strict vtable pointers");
2535 return builder.createPtrToInt(Visit(subExpr), cgf.convertType(destTy));
2536 }
2537 case CK_ToVoid:
2538 cgf.emitIgnoredExpr(subExpr);
2539 return {};
2540
2541 case CK_IntegralToFloating:
2542 case CK_FloatingToIntegral:
2543 case CK_FloatingCast:
2544 case CK_FixedPointToFloating:
2545 case CK_FloatingToFixedPoint: {
2546 if (kind == CK_FixedPointToFloating || kind == CK_FloatingToFixedPoint) {
2547 cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
2548 "fixed point casts");
2549 return {};
2550 }
2551 CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, ce);
2552 return emitScalarConversion(Visit(subExpr), subExpr->getType(), destTy,
2553 ce->getExprLoc());
2554 }
2555
2556 case CK_IntegralToBoolean:
2557 return emitIntToBoolConversion(Visit(subExpr),
2558 cgf.getLoc(ce->getSourceRange()));
2559
2560 case CK_PointerToBoolean:
2561 return emitPointerToBoolConversion(Visit(subExpr), subExpr->getType());
2562 case CK_FloatingToBoolean:
2563 return emitFloatToBoolConversion(Visit(subExpr),
2564 cgf.getLoc(subExpr->getExprLoc()));
2565 case CK_MemberPointerToBoolean: {
2566 mlir::Value memPtr = Visit(subExpr);
2567 return builder.createCast(cgf.getLoc(ce->getSourceRange()),
2568 cir::CastKind::member_ptr_to_bool, memPtr,
2569 cgf.convertType(destTy));
2570 }
2571
2572 case CK_VectorSplat: {
2573 // Create a vector object and fill all elements with the same scalar value.
2574 assert(destTy->isVectorType() && "CK_VectorSplat to non-vector type");
2575 return cir::VecSplatOp::create(builder,
2576 cgf.getLoc(subExpr->getSourceRange()),
2577 cgf.convertType(destTy), Visit(subExpr));
2578 }
2579 case CK_FunctionToPointerDecay:
2580 return cgf.emitLValue(subExpr).getPointer();
2581
2582 default:
2583 cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
2584 "CastExpr: ", ce->getCastKindName());
2585 }
2586 return {};
2587}
2588
2589mlir::Value ScalarExprEmitter::VisitCallExpr(const CallExpr *e) {
2591 return emitLoadOfLValue(e);
2592
2593 auto v = cgf.emitCallExpr(e).getValue();
2595 return v;
2596}
2597
2598mlir::Value ScalarExprEmitter::VisitMemberExpr(MemberExpr *e) {
2599 // TODO(cir): The classic codegen calls tryEmitAsConstant() here. Folding
2600 // constants sound like work for MLIR optimizers, but we'll keep an assertion
2601 // for now.
2603 Expr::EvalResult result;
2604 if (e->EvaluateAsInt(result, cgf.getContext(), Expr::SE_AllowSideEffects)) {
2605 llvm::APSInt value = result.Val.getInt();
2606 cgf.emitIgnoredExpr(e->getBase());
2607 mlir::Location loc = cgf.getLoc(e->getExprLoc());
2608 // The constant is folded from an APSInt with the source-type's bit width
2609 // (1 for bool), but the AST's expression type is what later consumers of
2610 // this value see. For a bool member we have to emit a !cir.bool constant
2611 // -- otherwise downstream ops (cir.call into a bool parameter, cir.if /
2612 // cir.ternary on the value, ...) would all reject the !cir.int<u, 1> the
2613 // raw APSInt would produce.
2614 if (e->getType()->isBooleanType())
2615 return builder.getBool(value.getBoolValue(), loc);
2616 return builder.getConstInt(loc, value);
2617 }
2618 return emitLoadOfLValue(e);
2619}
2620
2621mlir::Value ScalarExprEmitter::VisitInitListExpr(InitListExpr *e) {
2622 const unsigned numInitElements = e->getNumInits();
2623
2624 [[maybe_unused]] const bool ignore = std::exchange(ignoreResultAssign, false);
2625 assert((ignore == false ||
2626 (numInitElements == 0 && e->getType()->isVoidType())) &&
2627 "init list ignored");
2628
2629 if (e->hadArrayRangeDesignator()) {
2630 cgf.cgm.errorNYI(e->getSourceRange(), "ArrayRangeDesignator");
2631 return {};
2632 }
2633
2634 if (e->getType()->isVectorType()) {
2635 const auto vectorType =
2636 mlir::cast<cir::VectorType>(cgf.convertType(e->getType()));
2637
2638 SmallVector<mlir::Value, 16> elements;
2639 for (Expr *init : e->inits()) {
2640 elements.push_back(Visit(init));
2641 }
2642
2643 // Zero-initialize any remaining values.
2644 if (numInitElements < vectorType.getSize()) {
2645 const mlir::Value zeroValue = cgf.getBuilder().getNullValue(
2646 vectorType.getElementType(), cgf.getLoc(e->getSourceRange()));
2647 std::fill_n(std::back_inserter(elements),
2648 vectorType.getSize() - numInitElements, zeroValue);
2649 }
2650
2651 return cir::VecCreateOp::create(cgf.getBuilder(),
2652 cgf.getLoc(e->getSourceRange()), vectorType,
2653 elements);
2654 }
2655
2656 // C++11 value-initialization for the scalar.
2657 if (numInitElements == 0)
2658 return emitNullValue(e->getType(), cgf.getLoc(e->getExprLoc()));
2659
2660 return Visit(e->getInit(0));
2661}
2662
2663mlir::Value CIRGenFunction::emitScalarConversion(mlir::Value src,
2664 QualType srcTy, QualType dstTy,
2665 SourceLocation loc) {
2668 "Invalid scalar expression to emit");
2669 return ScalarExprEmitter(*this, builder)
2670 .emitScalarConversion(src, srcTy, dstTy, loc);
2671}
2672
2674 QualType srcTy,
2675 QualType dstTy,
2676 SourceLocation loc) {
2677 assert(srcTy->isAnyComplexType() && hasScalarEvaluationKind(dstTy) &&
2678 "Invalid complex -> scalar conversion");
2679
2680 QualType complexElemTy = srcTy->castAs<ComplexType>()->getElementType();
2681 if (dstTy->isBooleanType()) {
2682 auto kind = complexElemTy->isFloatingType()
2683 ? cir::CastKind::float_complex_to_bool
2684 : cir::CastKind::int_complex_to_bool;
2685 return builder.createCast(getLoc(loc), kind, src, convertType(dstTy));
2686 }
2687
2688 auto kind = complexElemTy->isFloatingType()
2689 ? cir::CastKind::float_complex_to_real
2690 : cir::CastKind::int_complex_to_real;
2691 mlir::Value real =
2692 builder.createCast(getLoc(loc), kind, src, convertType(complexElemTy));
2693 return emitScalarConversion(real, complexElemTy, dstTy, loc);
2694}
2695
2696mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *e) {
2697 // Perform vector logical not on comparison with zero vector.
2698 if (e->getType()->isVectorType() &&
2699 e->getType()->castAs<VectorType>()->getVectorKind() ==
2701 mlir::Value oper = Visit(e->getSubExpr());
2702 mlir::Location loc = cgf.getLoc(e->getExprLoc());
2703 auto operVecTy = mlir::cast<cir::VectorType>(oper.getType());
2704 auto exprVecTy = mlir::cast<cir::VectorType>(cgf.convertType(e->getType()));
2705 mlir::Value zeroVec = builder.getNullValue(operVecTy, loc);
2706 return cir::VecCmpOp::create(builder, loc, exprVecTy, cir::CmpOpKind::eq,
2707 oper, zeroVec);
2708 }
2709
2710 // Compare operand to zero.
2711 mlir::Value boolVal = cgf.evaluateExprAsBool(e->getSubExpr());
2712
2713 // Invert value.
2714 boolVal = builder.createNot(boolVal);
2715
2716 // ZExt result to the expr type.
2717 return maybePromoteBoolResult(boolVal, cgf.convertType(e->getType()));
2718}
2719
2720mlir::Value ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *e) {
2721 // Try folding the offsetof to a constant.
2722 Expr::EvalResult evalResult;
2723 if (e->EvaluateAsInt(evalResult, cgf.getContext())) {
2724 mlir::Type type = cgf.convertType(e->getType());
2725 llvm::APSInt value = evalResult.Val.getInt();
2726 return builder.getConstAPInt(cgf.getLoc(e->getExprLoc()), type, value);
2727 }
2728
2730 e->getSourceRange(),
2731 "ScalarExprEmitter::VisitOffsetOfExpr Can't eval expr as int");
2732 return {};
2733}
2734
2735mlir::Value ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *e) {
2736 QualType promotionTy = getPromotionType(e->getSubExpr()->getType());
2737 mlir::Value result = VisitRealImag(e, promotionTy);
2738 if (result && !promotionTy.isNull())
2739 result = emitUnPromotedValue(result, e->getType());
2740 return result;
2741}
2742
2743mlir::Value ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *e) {
2744 QualType promotionTy = getPromotionType(e->getSubExpr()->getType());
2745 mlir::Value result = VisitRealImag(e, promotionTy);
2746 if (result && !promotionTy.isNull())
2747 result = emitUnPromotedValue(result, e->getType());
2748 return result;
2749}
2750
2751mlir::Value ScalarExprEmitter::VisitRealImag(const UnaryOperator *e,
2752 QualType promotionTy) {
2753 assert(
2754 (e->getOpcode() == clang::UO_Real || e->getOpcode() == clang::UO_Imag) &&
2755 "Invalid UnaryOp kind for ComplexType Real or Imag");
2756
2757 Expr *op = e->getSubExpr();
2758 mlir::Location loc = cgf.getLoc(e->getExprLoc());
2759 if (op->getType()->isAnyComplexType()) {
2760 // If it's an l-value, load through the appropriate subobject l-value.
2761 // Note that we have to ask `e` because `op` might be an l-value that
2762 // this won't work for, e.g. an Obj-C property
2763 mlir::Value complex = cgf.emitComplexExpr(op);
2764 if (e->isGLValue() && !promotionTy.isNull()) {
2765 promotionTy = promotionTy->isAnyComplexType()
2766 ? promotionTy
2767 : cgf.getContext().getComplexType(promotionTy);
2768 complex = cgf.emitPromotedValue(complex, promotionTy);
2769 }
2770
2771 return e->getOpcode() == clang::UO_Real
2772 ? builder.createComplexReal(loc, complex)
2773 : builder.createComplexImag(loc, complex);
2774 }
2775
2776 if (e->getOpcode() == UO_Real) {
2777 mlir::Value operand = promotionTy.isNull()
2778 ? Visit(op)
2779 : cgf.emitPromotedScalarExpr(op, promotionTy);
2780 return builder.createComplexReal(loc, operand);
2781 }
2782
2783 // __imag on a scalar returns zero. Emit the subexpr to ensure side
2784 // effects are evaluated, but not the actual value.
2785 mlir::Value operand;
2786 if (op->isGLValue()) {
2787 operand = cgf.emitLValue(op).getPointer();
2788 operand = cir::LoadOp::create(builder, loc, operand);
2789 } else if (!promotionTy.isNull()) {
2790 operand = cgf.emitPromotedScalarExpr(op, promotionTy);
2791 } else {
2792 operand = cgf.emitScalarExpr(op);
2793 }
2794 return builder.createComplexImag(loc, operand);
2795}
2796
2797/// Return the size or alignment of the type of argument of the sizeof
2798/// expression as an integer.
2799mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
2800 const UnaryExprOrTypeTraitExpr *e) {
2801 const QualType typeToSize = e->getTypeOfArgument();
2802 const mlir::Location loc = cgf.getLoc(e->getSourceRange());
2803 if (auto kind = e->getKind();
2804 kind == UETT_SizeOf || kind == UETT_DataSizeOf || kind == UETT_CountOf) {
2805 if (const VariableArrayType *vat =
2806 cgf.getContext().getAsVariableArrayType(typeToSize)) {
2807 // For _Countof, we only want to evaluate if the extent is actually
2808 // variable as opposed to a multi-dimensional array whose extent is
2809 // constant but whose element type is variable.
2810 bool evaluateExtent = true;
2811 if (kind == UETT_CountOf && vat->getElementType()->isArrayType()) {
2812 evaluateExtent =
2813 !vat->getSizeExpr()->isIntegerConstantExpr(cgf.getContext());
2814 }
2815
2816 if (evaluateExtent) {
2817 if (e->isArgumentType()) {
2818 // sizeof(type) - make sure to emit the VLA size.
2819 cgf.emitVariablyModifiedType(typeToSize);
2820 } else {
2821 // C99 6.5.3.4p2: If the argument is an expression of type
2822 // VLA, it is evaluated.
2824 }
2825
2826 // For _Countof, we just want to return the size of a single dimension.
2827 if (kind == UETT_CountOf)
2828 return cgf.getVLAElements1D(vat).numElts;
2829
2830 // For sizeof and __datasizeof, we need to scale the number of elements
2831 // by the size of the array element type.
2832 CIRGenFunction::VlaSizePair vlaSize = cgf.getVLASize(vat);
2833 mlir::Value numElts = vlaSize.numElts;
2834
2835 // Scale the number of non-VLA elements by the non-VLA element size.
2836 CharUnits eltSize = cgf.getContext().getTypeSizeInChars(vlaSize.type);
2837 if (!eltSize.isOne()) {
2838 mlir::Location loc = cgf.getLoc(e->getSourceRange());
2839 mlir::Value eltSizeValue =
2840 builder.getConstAPInt(numElts.getLoc(), numElts.getType(),
2841 cgf.cgm.getSize(eltSize).getValue());
2842 return builder.createMul(loc, eltSizeValue, numElts,
2844 }
2845
2846 return numElts;
2847 }
2848 }
2849 } else if (e->getKind() == UETT_OpenMPRequiredSimdAlign) {
2851 cgf.getContext()
2854 .getQuantity();
2855 return builder.getConstantInt(loc, cgf.cgm.sizeTy, alignment);
2856 } else if (e->getKind() == UETT_VectorElements) {
2857 auto vecTy = cast<cir::VectorType>(convertType(e->getTypeOfArgument()));
2858 if (vecTy.getIsScalable()) {
2860 e->getSourceRange(),
2861 "VisitUnaryExprOrTypeTraitExpr: sizeOf scalable vector");
2862 return builder.getConstant(
2863 loc, cir::IntAttr::get(cgf.cgm.sizeTy,
2865 }
2866
2867 return builder.getConstant(
2868 loc, cir::IntAttr::get(cgf.cgm.sizeTy, vecTy.getSize()));
2869 }
2870
2871 // The result type is size_t (target-dependent width); use it so the IntAttr
2872 // width matches the APInt from EvaluateKnownConstInt.
2873 return builder.getConstant(
2874 loc, cir::IntAttr::get(cgf.cgm.sizeTy,
2876}
2877
2878/// Return true if the specified expression is cheap enough and side-effect-free
2879/// enough to evaluate unconditionally instead of conditionally. This is used
2880/// to convert control flow into selects in some cases.
2881/// TODO(cir): can be shared with LLVM codegen.
2883 CIRGenFunction &cgf) {
2884 // Anything that is an integer or floating point constant is fine.
2885 return e->IgnoreParens()->isEvaluatable(cgf.getContext());
2886
2887 // Even non-volatile automatic variables can't be evaluated unconditionally.
2888 // Referencing a thread_local may cause non-trivial initialization work to
2889 // occur. If we're inside a lambda and one of the variables is from the scope
2890 // outside the lambda, that function may have returned already. Reading its
2891 // locals is a bad idea. Also, these reads may introduce races there didn't
2892 // exist in the source-level program.
2893}
2894
2895mlir::Value ScalarExprEmitter::VisitAbstractConditionalOperator(
2896 const AbstractConditionalOperator *e) {
2897 CIRGenBuilderTy &builder = cgf.getBuilder();
2898 mlir::Location loc = cgf.getLoc(e->getSourceRange());
2899 ignoreResultAssign = false;
2900
2901 // Bind the common expression if necessary.
2902 CIRGenFunction::OpaqueValueMapping binding(cgf, e);
2903
2904 Expr *condExpr = e->getCond();
2905 Expr *lhsExpr = e->getTrueExpr();
2906 Expr *rhsExpr = e->getFalseExpr();
2907
2908 // If the condition constant folds and can be elided, try to avoid emitting
2909 // the condition and the dead arm.
2910 bool condExprBool;
2911 if (cgf.constantFoldsToBool(condExpr, condExprBool)) {
2912 Expr *live = lhsExpr, *dead = rhsExpr;
2913 if (!condExprBool)
2914 std::swap(live, dead);
2915
2916 // If the dead side doesn't have labels we need, just emit the Live part.
2917 if (!cgf.containsLabel(dead)) {
2918 if (condExprBool)
2920 mlir::Value result = Visit(live);
2921
2922 // If the live part is a throw expression, it acts like it has a void
2923 // type, so evaluating it returns a null Value. However, a conditional
2924 // with non-void type must return a non-null Value.
2925 if (!result && !e->getType()->isVoidType()) {
2926 result = builder.getConstant(
2927 loc, cir::PoisonAttr::get(builder.getContext(),
2928 cgf.convertType(e->getType())));
2929 }
2930
2931 return result;
2932 }
2933 }
2934
2935 QualType condType = condExpr->getType();
2936
2937 // OpenCL: If the condition is a vector, we can treat this condition like
2938 // the select function.
2939 if (cgf.getLangOpts().OpenCL &&
2940 (condType->isVectorType() || condType->isExtVectorType())) {
2942
2943 mlir::Value condValue = cgf.emitScalarExpr(condExpr);
2944 mlir::Value lhsValue = Visit(lhsExpr);
2945 mlir::Value rhsValue = Visit(rhsExpr);
2946
2947 mlir::Type vecTy = convertType(condType);
2948 mlir::Value zeroVec = builder.getNullValue(vecTy, loc);
2949 auto testMSB = cir::VecCmpOp::create(
2950 builder, loc, vecTy, cir::CmpOpKind::lt, condValue, zeroVec);
2951 mlir::Value tmp = builder.createIntCast(testMSB, vecTy);
2952 mlir::Value tmp2 = builder.createNot(tmp);
2953
2954 // Cast float to int to perform ANDs if necessary.
2955 mlir::Value rhsTmp = rhsValue;
2956 mlir::Value lhsTmp = lhsValue;
2957 bool wasCast = false;
2958 auto rhsVecTy = cast<cir::VectorType>(rhsValue.getType());
2959 if (cir::isAnyFloatingPointType(rhsVecTy.getElementType())) {
2960 rhsTmp = builder.createBitcast(rhsValue, tmp2.getType());
2961 lhsTmp = builder.createBitcast(lhsValue, tmp.getType());
2962 wasCast = true;
2963 }
2964
2965 mlir::Value tmp3 = builder.createAnd(loc, rhsTmp, tmp2);
2966 mlir::Value tmp4 = builder.createAnd(loc, lhsTmp, tmp);
2967 mlir::Value tmp5 = builder.createOr(loc, tmp3, tmp4);
2968 if (wasCast)
2969 tmp5 = builder.createBitcast(tmp5, rhsValue.getType());
2970 return tmp5;
2971 }
2972
2973 if (condType->isVectorType() || condType->isSveVLSBuiltinType()) {
2974 if (!condType->isVectorType()) {
2976 cgf.cgm.errorNYI(loc, "TernaryOp for SVE vector");
2977 return {};
2978 }
2979
2980 mlir::Value condValue = Visit(condExpr);
2981 mlir::Value lhsValue = Visit(lhsExpr);
2982 mlir::Value rhsValue = Visit(rhsExpr);
2983 return cir::VecTernaryOp::create(builder, loc, condValue, lhsValue,
2984 rhsValue);
2985 }
2986
2987 // If this is a really simple expression (like x ? 4 : 5), emit this as a
2988 // select instead of as control flow. We can only do this if it is cheap
2989 // and safe to evaluate the LHS and RHS unconditionally.
2990 if (isCheapEnoughToEvaluateUnconditionally(lhsExpr, cgf) &&
2992 bool lhsIsVoid = false;
2993 mlir::Value condV = cgf.evaluateExprAsBool(condExpr);
2995
2996 mlir::Value lhs = Visit(lhsExpr);
2997 if (!lhs) {
2998 lhs = builder.getNullValue(cgf.voidTy, loc);
2999 lhsIsVoid = true;
3000 }
3001
3002 mlir::Value rhs = Visit(rhsExpr);
3003 if (lhsIsVoid) {
3004 assert(!rhs && "lhs and rhs types must match");
3005 rhs = builder.getNullValue(cgf.voidTy, loc);
3006 }
3007
3008 return builder.createSelect(loc, condV, lhs, rhs);
3009 }
3010
3011 mlir::Value condV = cgf.emitOpOnBoolExpr(loc, condExpr);
3012 CIRGenFunction::ConditionalEvaluation eval(cgf);
3013
3014 auto emitBranch = [&](mlir::OpBuilder &b, mlir::Location loc, Expr *expr) {
3015 CIRGenFunction::LexicalScope lexScope{cgf, loc, b.getInsertionBlock()};
3017
3018 mlir::Value branch;
3019 {
3020 // Emit any cleanups that were needed on this branch so we can spill
3021 // and reload the return value.
3022 CIRGenFunction::RunCleanupsScope branchCleanups(cgf);
3024 eval.beginEvaluation();
3025 branch = Visit(expr);
3026 eval.endEvaluation();
3027 branchCleanups.forceCleanup({&branch});
3028 }
3029
3030 if (branch)
3031 cir::YieldOp::create(b, loc, branch);
3032 };
3033
3034 cir::TernaryOp ternary = cir::TernaryOp::create(
3035 builder, loc, condV,
3036 /*trueBuilder=*/
3037 [&](mlir::OpBuilder &b, mlir::Location loc) {
3038 emitBranch(b, loc, lhsExpr);
3039 },
3040 /*falseBuilder=*/
3041 [&](mlir::OpBuilder &b, mlir::Location loc) {
3042 emitBranch(b, loc, rhsExpr);
3043 });
3044
3045 // Only a void arm can be left unterminated (a noreturn arm already ends
3046 // in cir.unreachable); close it with an empty cir.yield.
3047 for (mlir::Region *region :
3048 {&ternary.getTrueRegion(), &ternary.getFalseRegion()}) {
3049 mlir::Block &lastBlock = region->back();
3050 if (lastBlock.empty() ||
3051 !lastBlock.back().hasTrait<mlir::OpTrait::IsTerminator>()) {
3052 mlir::OpBuilder::InsertionGuard guard(builder);
3053 builder.setInsertionPointToEnd(&lastBlock);
3054 cir::YieldOp::create(builder, loc);
3055 }
3056 }
3057
3058 return ternary.getResult();
3059}
3060
3062 LValue lv) {
3063 return ScalarExprEmitter(*this, builder).emitScalarPrePostIncDec(e, lv);
3064}
static Value * createCastsForTypeOfSameSize(CGBuilderTy &Builder, const llvm::DataLayout &DL, Value *Src, llvm::Type *DstTy, StringRef Name="")
#define HANDLE_BINOP(OP)
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 mlir::Value tryEmitFMulAdd(mlir::Location loc, const BinOpInfo &op, CIRGenBuilderTy &builder, bool isSub=false)
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 mlir::Value buildFMulAdd(mlir::Location addLoc, cir::FMulOp mulOp, mlir::Value addend, CIRGenBuilderTy &builder, bool negMul, bool negAdd)
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)
static bool isIntegerVectorBinOp(mlir::Type ty)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
mlir::Value createNSWSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::ConstantOp getBool(bool state, mlir::Location loc)
mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ, const llvm::APInt &val)
mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob=OverflowBehavior::None)
mlir::Value createNSWAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc)
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr)
mlir::Value createOr(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createCast(mlir::Location loc, cir::CastKind kind, mlir::Value src, mlir::Type newTy)
mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy)
mlir::Value createPtrToInt(mlir::Value src, mlir::Type newTy)
mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob=OverflowBehavior::None)
mlir::Value createFNeg(mlir::Location loc, mlir::Value operand)
mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand)
mlir::Value createNSWMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc)
mlir::Value createShiftLeft(mlir::Location loc, mlir::Value lhs, unsigned bits)
mlir::Value createAnd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createIntCast(mlir::Value src, mlir::Type newTy)
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
mlir::Value createNot(mlir::Location loc, mlir::Value value)
mlir::Value createSelect(mlir::Location loc, mlir::Value condition, mlir::Value trueValue, mlir::Value falseValue)
mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob=OverflowBehavior::None)
cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty, int64_t value)
mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real, mlir::Value imag)
mlir::Value createFRem(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createShiftRight(mlir::Location loc, mlir::Value lhs, unsigned bits)
mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs)
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand)
mlir::Type getIntPtrType(mlir::Type ty) const
llvm::APInt getValue() const
APSInt & getInt()
Definition APValue.h:511
bool isNullPointer() const
Definition APValue.cpp:1056
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
CanQualType FloatTy
QualType getVectorType(QualType VectorType, unsigned NumElts, VectorKind VecKind) const
Return the unique reference to a vector type of the specified element type and size.
CanQualType BoolTy
unsigned getOpenMPDefaultSimdAlign(QualType T) const
Get default simd alignment of the specified complete type in bits.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
const VariableArrayType * getAsVariableArrayType(QualType T) const
QualType getComplexType(QualType T) const
Return the uniqued reference to the type for a complex number with the specified element type.
CharUnits toCharUnitsFromBits(int64_t BitSize) const
Convert a size in bits to a size in characters.
bool isPromotableIntegerType(QualType T) const
More type predicates useful for type checking/promotion.
static bool hasSameUnqualifiedType(QualType T1, QualType T2)
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
Expr * getCond() const
getCond - Return the expression representing the condition for the ?
Definition Expr.h:4542
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
Definition Expr.h:4548
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Definition Expr.h:4554
LabelDecl * getLabel() const
Definition Expr.h:4584
uint64_t getValue() const
Definition ExprCXX.h:3047
Expr * getSrcExpr() const
getSrcExpr - Return the Expr to be converted.
Definition Expr.h:6769
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:4049
Expr * getLHS() const
Definition Expr.h:4099
SourceLocation getExprLoc() const
Definition Expr.h:4090
Expr * getRHS() const
Definition Expr.h:4101
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const
Get the FP features status of this operator.
Definition Expr.h:4262
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:2214
Opcode getOpcode() const
Definition Expr.h:4094
BinaryOperatorKind Opcode
Definition Expr.h:4054
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const
Return address with different element type, a bitcast pointer, and the same alignment.
mlir::Value createNeg(mlir::Location loc, mlir::Value value, bool nsw=false)
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
void forceCleanup(ArrayRef< mlir::Value * > valuesToReload={})
Force the emission of cleanups now, instead of waiting until this object is destroyed.
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)
mlir::Value emitPromotedValue(mlir::Value result, QualType promotionType)
Address emitPointerWithAlignment(const clang::Expr *expr, LValueBaseInfo *baseInfo=nullptr)
Given an expression with a pointer type, emit the value and compute our best estimate of the alignmen...
void emitVariablyModifiedType(QualType ty)
const clang::LangOptions & getLangOpts() const
VlaSizePair getVLASize(const VariableArrayType *type)
Returns an MLIR::Value+QualType pair that corresponds to the size, in non-variably-sized elements,...
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.
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,...
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).
VlaSizePair getVLAElements1D(const VariableArrayType *vla)
Return the number of elements for a single dimension for the given array type.
mlir::Value performAddrSpaceCast(mlir::Value v, mlir::Type destTy) const
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...
Address getAddressOfDerivedClass(mlir::Location loc, Address baseAddr, const CXXRecordDecl *derived, llvm::iterator_range< CastExpr::path_const_iterator > path, bool nullCheckValue)
clang::SanitizerSet sanOpts
Sanitizers enabled for this function.
mlir::Type convertTypeForMem(QualType t)
LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e)
mlir::Value getAsNaturalPointerTo(Address addr, QualType pointeeType)
mlir::Value emitScalarExpr(const clang::Expr *e, bool ignoreResultAssign=false)
Emit the computation of the specified expression of scalar type.
mlir::Value emitPromotedScalarExpr(const Expr *e, QualType promotionType)
bool shouldNullCheckClassCastValue(const CastExpr *ce)
CIRGenBuilderTy & getBuilder()
mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv)
bool containsLabel(const clang::Stmt *s, bool ignoreCaseStmts=false)
Return true if the statement contains a label in it.
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)
clang::ASTContext & getContext() const
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...
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 ...
void emitIgnoredExpr(const clang::Expr *e)
Emit code to compute the specified expression, ignoring the result.
mlir::Value emitDynamicCast(Address thisAddr, const CXXDynamicCastExpr *dce)
CharUnits computeNonVirtualBaseClassOffset(const CXXRecordDecl *derivedClass, llvm::iterator_range< CastExpr::path_const_iterator > path)
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
mlir::IntegerAttr getSize(CharUnits size)
const cir::CIRDataLayout getDataLayout() const
const clang::CodeGenOptions & getCodeGenOpts() const
mlir::TypedAttr emitNullMemberAttr(QualType t, const MemberPointerType *mpt)
Returns a null attribute to represent either a null method or null data member, depending on the type...
mlir::Value emitNullConstant(QualType t, mlir::Location loc)
Return the result of value-initializing the given type, i.e.
mlir::Value getPointer() const
static RValue get(mlir::Value v)
Definition CIRGenValue.h:83
mlir::Value getValue() const
Return the value of this scalar value.
Definition CIRGenValue.h:57
bool getValue() const
Definition ExprCXX.h:743
Expr * getExpr()
Get the initialization expression that will be used.
Definition ExprCXX.cpp:1112
bool getValue() const
Definition ExprCXX.h:4331
Expr * getSemanticForm()
Get an equivalent semantic form for this expression.
Definition ExprCXX.h:307
QualType getCallReturnType(const ASTContext &Ctx) const
getCallReturnType - Get the return type of the call expr.
Definition Expr.cpp:1609
CastKind getCastKind() const
Definition Expr.h:3731
llvm::iterator_range< path_iterator > path()
Path through the class hierarchy taken by casts between base and derived classes (see implementation ...
Definition Expr.h:3774
bool changesVolatileQualification() const
Return.
Definition Expr.h:3821
static const char * getCastKindName(CastKind CK)
Definition Expr.cpp:1959
Expr * getSubExpr()
Definition Expr.h:3737
int64_t QuantityType
Definition CharUnits.h:40
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
bool isOne() const
isOne - Test whether the quantity equals one.
Definition CharUnits.h:125
unsigned getValue() const
Definition Expr.h:1640
Expr * getChosenSubExpr() const
getChosenSubExpr - Return the subexpression chosen according to the condition.
Definition Expr.h:4895
Complex values, per C99 6.2.5p11.
Definition TypeBase.h:3355
CompoundAssignOperator - For compound assignments (e.g.
Definition Expr.h:4311
QualType getComputationLHSType() const
Definition Expr.h:4345
QualType getComputationResultType() const
Definition Expr.h:4348
SourceLocation getExprLoc() const LLVM_READONLY
bool isSatisfied() const
Whether or not the concept with the given arguments was satisfied when the expression was created.
Expr * getSrcExpr() const
getSrcExpr - Return the Expr to be converted.
Definition Expr.h:4820
ChildElementIter< false > begin()
Definition Expr.h:5252
size_t getDataElementCount() const
Definition Expr.h:5168
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:686
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) 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:3097
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...
bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsRValue - Return true if this is a constant which we can fold to an rvalue using any crazy t...
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3081
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:283
QualType getType() const
Definition Expr.h:144
bool allowFPContractWithinStatement() const
llvm::APInt getValue() const
Returns an internal integer representation of the literal.
Definition Expr.h:1586
llvm::APFloat getValue() const
Definition Expr.h:1677
const Expr * getSubExpr() const
Definition Expr.h:1073
Expr * getResultExpr()
Return the result expression of this controlling expression.
Definition Expr.h:6485
unsigned getNumInits() const
Definition Expr.h:5352
bool hadArrayRangeDesignator() const
Definition Expr.h:5500
const Expr * getInit(unsigned Init) const
Definition Expr.h:5374
ArrayRef< Expr * > inits() const
Definition Expr.h:5372
bool isSignedOverflowDefined() const
Expr * getBase() const
Definition Expr.h:3452
SourceLocation getExprLoc() const LLVM_READONLY
Definition Expr.h:3570
A pointer to member type per C++ 8.3.3 - Pointers to members.
Definition TypeBase.h:3767
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
SourceRange getSourceRange() const LLVM_READONLY
Definition ExprObjC.h:248
SourceRange getSourceRange() const
Definition ExprObjC.h:1755
SourceRange getSourceRange() const LLVM_READONLY
Definition ExprObjC.h:190
SourceRange getSourceRange() const LLVM_READONLY
Definition ExprObjC.h:415
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
Definition Expr.h:2538
SourceLocation getExprLoc() const LLVM_READONLY
Definition Expr.h:1219
Expr * getSelectedExpr() const
Definition ExprCXX.h:4638
const Expr * getSubExpr() const
Definition Expr.h:2210
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3408
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8504
Qualifiers::ObjCLifetime getObjCLifetime() const
Returns lifetime attribute of this type.
Definition TypeBase.h:1454
QualType getCanonicalType() const
Definition TypeBase.h:8556
bool UseExcessPrecision(const ASTContext &Ctx)
Definition Type.cpp:1679
bool isCanonical() const
Definition TypeBase.h:8561
@ OCL_Strong
Assigning into this object requires the old value to be released and the new value to be retained.
Definition TypeBase.h:362
@ OCL_ExplicitNone
This object can be modified without requiring retains or releases.
Definition TypeBase.h:355
@ OCL_None
There is no lifetime qualification on this type.
Definition TypeBase.h:351
@ OCL_Weak
Reading or writing from this object requires a barrier call.
Definition TypeBase.h:365
@ OCL_Autoreleasing
Assigning into this object requires a lifetime extension.
Definition TypeBase.h:368
bool isSatisfied() const
Whether or not the requires clause is satisfied.
unsigned getNumSubExprs() const
getNumSubExprs - Return the size of the SubExprs array.
Definition Expr.h:4687
Expr * getExpr(unsigned Index)
getExpr - Return the Expr at the specified index.
Definition Expr.h:4693
unsigned getPackLength() const
Retrieve the length of the parameter pack.
Definition ExprCXX.h:4514
APValue EvaluateInContext(const ASTContext &Ctx, const Expr *DefaultExpr) const
Return the result of evaluating this SourceLocExpr in the specified (and possibly null) default argum...
Definition Expr.cpp:2291
SourceLocation getLocation() const
Definition Expr.h:5081
Encodes a location in the source.
SourceLocation getBegin() const
CompoundStmt * getSubStmt()
Definition Expr.h:4623
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
const char * getStmtClassName() const
Definition Stmt.cpp:86
bool getBoolValue() const
Definition ExprCXX.h:2950
const APValue & getAPValue() const
Definition ExprCXX.h:2955
bool isStoredAsBoolean() const
Definition ExprCXX.h:2946
bool isVoidType() const
Definition TypeBase.h:9113
bool isBooleanType() const
Definition TypeBase.h:9250
bool isSignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...
Definition Type.cpp:2319
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition Type.cpp:2296
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isConstantMatrixType() const
Definition TypeBase.h:8908
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9157
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9407
bool isReferenceType() const
Definition TypeBase.h:8765
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
Definition Type.cpp:1984
bool isSveVLSBuiltinType() const
Determines if this is a sizeless type supported by the 'arm_sve_vector_bits' type attribute,...
Definition Type.cpp:2731
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool hasUnsignedIntegerRepresentation() const
Determine whether this type has an unsigned integer representation of some sort, e....
Definition Type.cpp:2406
bool isExtVectorType() const
Definition TypeBase.h:8884
bool isExtVectorBoolType() const
Definition TypeBase.h:8888
bool isAnyComplexType() const
Definition TypeBase.h:8876
bool isFixedPointType() const
Return true if this is a fixed point type according to ISO/IEC JTC1 SC22 WG14 N1169.
Definition TypeBase.h:9173
bool isHalfType() const
Definition TypeBase.h:9117
bool hasSignedIntegerRepresentation() const
Determine whether this type has an signed integer representation of some sort, e.g....
Definition Type.cpp:2340
bool isMatrixType() const
Definition TypeBase.h:8904
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition TypeBase.h:2877
bool isMemberFunctionPointerType() const
Definition TypeBase.h:8826
bool isVectorType() const
Definition TypeBase.h:8880
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2435
bool isFloatingType() const
Definition Type.cpp:2419
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:2362
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9340
bool isNullPtrType() const
Definition TypeBase.h:9150
QualType getTypeOfArgument() const
Gets the argument type, or the type of the argument expression, whichever is appropriate.
Definition Expr.h:2705
UnaryExprOrTypeTrait getKind() const
Definition Expr.h:2668
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition Expr.h:2255
SourceLocation getExprLoc() const
Definition Expr.h:2379
Expr * getSubExpr() const
Definition Expr.h:2296
Opcode getOpcode() const
Definition Expr.h:2291
static bool isIncrementOp(Opcode Op)
Definition Expr.h:2337
static bool isPrefix(Opcode Op)
isPrefix - Return true if this is a prefix operation, like –x.
Definition Expr.h:2330
bool canOverflow() const
Returns true if the unary operator can cause an overflow.
Definition Expr.h:2309
Represents a C array with a specified size that is not an integer-constant-expression.
Definition TypeBase.h:4080
Represents a GCC generic vector type.
Definition TypeBase.h:4289
VectorKind getVectorKind() const
Definition TypeBase.h:4309
OverflowBehavior
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 AstTypeMatcher< PointerType > pointerType
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
@ Address
A pointer to a ValueDecl.
Definition Primitives.h:28
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ Type
The name was classified as a type.
Definition Sema.h:559
CastKind
CastKind - The kind of operation required for a conversion.
@ Generic
not a target-specific vector type
Definition TypeBase.h:4250
U cast(CodeGen::Address addr)
Definition Address.h:327
long int64_t
#define false
Definition stdbool.h:26
static bool instrumentation()
static bool dataMemberType()
static bool objCLifetime()
static bool addressSpace()
static bool fixedPointType()
static bool vecTernaryOp()
static bool addHeapAllocSiteMetadata()
static bool mayHaveIntegerOverflow()
static bool fastMathFlags()
static bool tryEmitAsConstant()
static bool llvmLoweringPtrDiffConsidersPointee()
static bool scalableVectors()
static bool memberFuncPtrAuthInfo()
static bool emitLValueAlignmentAssumption()
static bool incrementProfileCounter()
EvalResult is a struct with detailed info about an evaluated expression.
Definition Expr.h:657
APValue Val
Val - This is the value the expression can be folded to.
Definition Expr.h:659
bool HasSideEffects
Whether the evaluated expression has side effects.
Definition Expr.h:616
bool has(SanitizerMask K) const
Check if a certain (single) sanitizer is enabled.
Definition Sanitizers.h:174