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