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