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