20#include "mlir/IR/Location.h"
21#include "mlir/IR/Value.h"
43 bool isDivRemOp()
const {
44 return opcode == BO_Div || opcode == BO_Rem || opcode == BO_DivAssign ||
45 opcode == BO_RemAssign;
49 bool mayHaveIntegerOverflow()
const {
51 auto lhsci = lhs.getDefiningOp<cir::ConstantOp>();
52 auto rhsci = rhs.getDefiningOp<cir::ConstantOp>();
64 bool isFixedPointOp()
const {
67 if (
const auto *binOp = llvm::dyn_cast<BinaryOperator>(e)) {
68 QualType lhstype = binOp->getLHS()->getType();
69 QualType rhstype = binOp->getRHS()->getType();
72 if (
const auto *unop = llvm::dyn_cast<UnaryOperator>(e))
73 return unop->getSubExpr()->getType()->isFixedPointType();
78class ScalarExprEmitter :
public StmtVisitor<ScalarExprEmitter, mlir::Value> {
80 CIRGenBuilderTy &builder;
84 bool ignoreResultAssign;
87 ScalarExprEmitter(CIRGenFunction &cgf, CIRGenBuilderTy &builder,
88 bool ignoreResultAssign =
false)
89 : cgf(cgf), builder(builder), ignoreResultAssign(ignoreResultAssign) {}
95 mlir::Value emitComplexToScalarConversion(mlir::Location loc,
99 mlir::Value emitNullValue(QualType ty, mlir::Location loc) {
100 return cgf.cgm.emitNullConstant(ty, loc);
103 mlir::Value emitPromotedValue(mlir::Value result, QualType promotionType) {
104 return builder.createFloatingCast(result, cgf.convertType(promotionType));
107 mlir::Value emitUnPromotedValue(mlir::Value result, QualType exprType) {
108 return builder.createFloatingCast(result, cgf.convertType(exprType));
111 mlir::Value emitPromoted(
const Expr *e, QualType promotionType);
113 mlir::Value maybePromoteBoolResult(mlir::Value value,
114 mlir::Type dstTy)
const {
115 if (mlir::isa<cir::IntType>(dstTy))
116 return builder.createBoolToInt(value, dstTy);
117 if (mlir::isa<cir::BoolType>(dstTy))
119 llvm_unreachable(
"Can only promote integer or boolean types");
126 mlir::Value Visit(Expr *e) {
127 return StmtVisitor<ScalarExprEmitter, mlir::Value>::Visit(e);
130 mlir::Value VisitStmt(Stmt *
s) {
131 llvm_unreachable(
"Statement passed to ScalarExprEmitter");
134 mlir::Value VisitExpr(Expr *e) {
135 cgf.getCIRGenModule().errorNYI(
140 mlir::Value VisitPackIndexingExpr(PackIndexingExpr *e) {
144 mlir::Value VisitParenExpr(ParenExpr *pe) {
return Visit(pe->
getSubExpr()); }
146 mlir::Value VisitGenericSelectionExpr(GenericSelectionExpr *ge) {
151 mlir::Value emitLoadOfLValue(
const Expr *e) {
152 LValue lv = cgf.emitLValue(e);
154 return cgf.emitLoadOfLValue(lv, e->
getExprLoc()).getValue();
157 mlir::Value emitLoadOfLValue(LValue lv, SourceLocation loc) {
158 return cgf.emitLoadOfLValue(lv, loc).getValue();
162 mlir::Value VisitDeclRefExpr(DeclRefExpr *e) {
163 if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(e))
164 return cgf.emitScalarConstant(constant, e);
166 return emitLoadOfLValue(e);
169 mlir::Value VisitIntegerLiteral(
const IntegerLiteral *e) {
171 return cir::ConstantOp::create(builder, cgf.getLoc(e->
getExprLoc()),
175 mlir::Value VisitFloatingLiteral(
const FloatingLiteral *e) {
177 assert(mlir::isa<cir::FPTypeInterface>(
type) &&
178 "expect floating-point type");
179 return cir::ConstantOp::create(builder, cgf.getLoc(e->
getExprLoc()),
183 mlir::Value VisitCharacterLiteral(
const CharacterLiteral *e) {
184 mlir::Type ty = cgf.convertType(e->
getType());
185 auto init = cir::IntAttr::get(ty, e->
getValue());
186 return cir::ConstantOp::create(builder, cgf.getLoc(e->
getExprLoc()), init);
189 mlir::Value VisitCXXBoolLiteralExpr(
const CXXBoolLiteralExpr *e) {
193 mlir::Value VisitCXXScalarValueInitExpr(
const CXXScalarValueInitExpr *e) {
200 mlir::Value VisitOpaqueValueExpr(OpaqueValueExpr *e) {
202 return emitLoadOfLValue(cgf.getOrCreateOpaqueLValueMapping(e),
206 return cgf.getOrCreateOpaqueRValueMapping(e).getValue();
209 mlir::Value VisitCastExpr(
CastExpr *e);
210 mlir::Value VisitCallExpr(
const CallExpr *e);
212 mlir::Value VisitStmtExpr(StmtExpr *e) {
213 CIRGenFunction::StmtExprEvaluation eval(cgf);
221 (void)cgf.emitCompoundStmt(*e->
getSubStmt(), &retAlloca);
223 return cgf.emitLoadOfScalar(cgf.makeAddrLValue(retAlloca, e->
getType()),
227 mlir::Value VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
228 ignoreResultAssign =
false;
234 const mlir::Value vecValue = Visit(e->
getBase());
235 const mlir::Value indexValue = Visit(e->
getIdx());
236 return cir::VecExtractOp::create(cgf.builder, loc, vecValue, indexValue);
239 return emitLoadOfLValue(e);
242 mlir::Value VisitShuffleVectorExpr(ShuffleVectorExpr *e) {
245 mlir::Value inputVec = Visit(e->
getExpr(0));
246 mlir::Value indexVec = Visit(e->
getExpr(1));
247 return cir::VecShuffleDynamicOp::create(
248 cgf.builder, cgf.getLoc(e->
getSourceRange()), inputVec, indexVec);
251 mlir::Value vec1 = Visit(e->
getExpr(0));
252 mlir::Value vec2 = Visit(e->
getExpr(1));
257 SmallVector<mlir::Attribute, 8> indices;
260 cir::IntAttr::get(cgf.builder.getSInt64Ty(),
266 return cir::VecShuffleOp::create(cgf.builder,
268 cgf.convertType(e->
getType()), vec1, vec2,
269 cgf.builder.getArrayAttr(indices));
272 mlir::Value VisitConvertVectorExpr(ConvertVectorExpr *e) {
275 return emitScalarConversion(Visit(e->
getSrcExpr()),
280 mlir::Value VisitMemberExpr(MemberExpr *e);
282 mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
283 return emitLoadOfLValue(e);
286 mlir::Value VisitInitListExpr(InitListExpr *e);
288 mlir::Value VisitExplicitCastExpr(ExplicitCastExpr *e) {
289 return VisitCastExpr(e);
292 mlir::Value VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *e) {
293 return cgf.cgm.emitNullConstant(e->
getType(),
298 mlir::Value emitPointerToBoolConversion(mlir::Value v, QualType qt) {
301 return cgf.getBuilder().createPtrToBoolCast(v);
304 mlir::Value emitFloatToBoolConversion(mlir::Value src, mlir::Location loc) {
305 cir::BoolType boolTy = builder.getBoolTy();
306 return cir::CastOp::create(builder, loc, boolTy,
307 cir::CastKind::float_to_bool, src);
310 mlir::Value emitIntToBoolConversion(mlir::Value srcVal, mlir::Location loc) {
316 cir::BoolType boolTy = builder.getBoolTy();
317 return cir::CastOp::create(builder, loc, boolTy, cir::CastKind::int_to_bool,
323 mlir::Value emitConversionToBool(mlir::Value src, QualType srcType,
324 mlir::Location loc) {
325 assert(srcType.
isCanonical() &&
"EmitScalarConversion strips typedefs");
328 return emitFloatToBoolConversion(src, loc);
330 if (llvm::isa<MemberPointerType>(srcType)) {
331 cgf.getCIRGenModule().errorNYI(loc,
"member pointer to bool conversion");
332 return builder.getFalse(loc);
336 return emitIntToBoolConversion(src, loc);
338 assert(::mlir::isa<cir::PointerType>(src.getType()));
339 return emitPointerToBoolConversion(src, srcType);
344 struct ScalarConversionOpts {
345 bool treatBooleanAsSigned;
346 bool emitImplicitIntegerTruncationChecks;
347 bool emitImplicitIntegerSignChangeChecks;
349 ScalarConversionOpts()
350 : treatBooleanAsSigned(
false),
351 emitImplicitIntegerTruncationChecks(
false),
352 emitImplicitIntegerSignChangeChecks(
false) {}
354 ScalarConversionOpts(clang::SanitizerSet sanOpts)
355 : treatBooleanAsSigned(
false),
356 emitImplicitIntegerTruncationChecks(
357 sanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)),
358 emitImplicitIntegerSignChangeChecks(
359 sanOpts.
has(SanitizerKind::ImplicitIntegerSignChange)) {}
366 mlir::Value emitScalarCast(mlir::Value src, QualType srcType,
367 QualType dstType, mlir::Type srcTy,
368 mlir::Type dstTy, ScalarConversionOpts opts) {
370 "Internal error: matrix types not handled by this function.");
371 assert(!(mlir::isa<mlir::IntegerType>(srcTy) ||
372 mlir::isa<mlir::IntegerType>(dstTy)) &&
373 "Obsolete code. Don't use mlir::IntegerType with CIR.");
375 mlir::Type fullDstTy = dstTy;
376 if (mlir::isa<cir::VectorType>(srcTy) &&
377 mlir::isa<cir::VectorType>(dstTy)) {
379 srcTy = mlir::dyn_cast<cir::VectorType>(srcTy).getElementType();
380 dstTy = mlir::dyn_cast<cir::VectorType>(dstTy).getElementType();
383 std::optional<cir::CastKind> castKind;
385 if (mlir::isa<cir::BoolType>(srcTy)) {
386 if (opts.treatBooleanAsSigned)
387 cgf.getCIRGenModule().errorNYI(
"signed bool");
388 if (cgf.getBuilder().isInt(dstTy))
389 castKind = cir::CastKind::bool_to_int;
390 else if (mlir::isa<cir::FPTypeInterface>(dstTy))
391 castKind = cir::CastKind::bool_to_float;
393 llvm_unreachable(
"Internal error: Cast to unexpected type");
394 }
else if (cgf.getBuilder().isInt(srcTy)) {
395 if (cgf.getBuilder().isInt(dstTy))
396 castKind = cir::CastKind::integral;
397 else if (mlir::isa<cir::FPTypeInterface>(dstTy))
398 castKind = cir::CastKind::int_to_float;
400 llvm_unreachable(
"Internal error: Cast to unexpected type");
401 }
else if (mlir::isa<cir::FPTypeInterface>(srcTy)) {
402 if (cgf.getBuilder().isInt(dstTy)) {
406 if (!cgf.cgm.getCodeGenOpts().StrictFloatCastOverflow)
407 cgf.getCIRGenModule().errorNYI(
"strict float cast overflow");
409 castKind = cir::CastKind::float_to_int;
410 }
else if (mlir::isa<cir::FPTypeInterface>(dstTy)) {
412 return builder.createFloatingCast(src, fullDstTy);
414 llvm_unreachable(
"Internal error: Cast to unexpected type");
417 llvm_unreachable(
"Internal error: Cast from unexpected type");
420 assert(castKind.has_value() &&
"Internal error: CastKind not set.");
421 return cir::CastOp::create(builder, src.getLoc(), fullDstTy, *castKind,
426 VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e) {
430 mlir::Value VisitVAArgExpr(VAArgExpr *ve) {
435 "variably modified types in varargs");
438 return cgf.emitVAArg(ve);
441 mlir::Value VisitUnaryExprOrTypeTraitExpr(
const UnaryExprOrTypeTraitExpr *e);
443 VisitAbstractConditionalOperator(
const AbstractConditionalOperator *e);
446 mlir::Value VisitUnaryPostDec(
const UnaryOperator *e) {
448 return emitScalarPrePostIncDec(e, lv, cir::UnaryOpKind::Dec,
false);
450 mlir::Value VisitUnaryPostInc(
const UnaryOperator *e) {
452 return emitScalarPrePostIncDec(e, lv, cir::UnaryOpKind::Inc,
false);
454 mlir::Value VisitUnaryPreDec(
const UnaryOperator *e) {
456 return emitScalarPrePostIncDec(e, lv, cir::UnaryOpKind::Dec,
true);
458 mlir::Value VisitUnaryPreInc(
const UnaryOperator *e) {
460 return emitScalarPrePostIncDec(e, lv, cir::UnaryOpKind::Inc,
true);
462 mlir::Value emitScalarPrePostIncDec(
const UnaryOperator *e, LValue lv,
463 cir::UnaryOpKind kind,
bool isPre) {
464 if (cgf.getLangOpts().OpenMP)
472 if (
type->getAs<AtomicType>()) {
476 value = cgf.emitLoadOfLValue(lv, e->
getExprLoc()).getValue();
479 value = cgf.emitLoadOfLValue(lv, e->
getExprLoc()).getValue();
492 if (kind == cir::UnaryOpKind::Inc &&
type->isBooleanType()) {
493 value = builder.getTrue(cgf.getLoc(e->
getExprLoc()));
494 }
else if (
type->isIntegerType()) {
495 QualType promotedType;
496 [[maybe_unused]]
bool canPerformLossyDemotionCheck =
false;
497 if (cgf.getContext().isPromotableIntegerType(
type)) {
498 promotedType = cgf.getContext().getPromotedIntegerType(
type);
499 assert(promotedType !=
type &&
"Shouldn't promote to the same type.");
500 canPerformLossyDemotionCheck =
true;
501 canPerformLossyDemotionCheck &=
502 cgf.getContext().getCanonicalType(
type) !=
503 cgf.getContext().getCanonicalType(promotedType);
504 canPerformLossyDemotionCheck &=
511 (!canPerformLossyDemotionCheck ||
512 type->isSignedIntegerOrEnumerationType() ||
514 mlir::cast<cir::IntType>(cgf.convertType(
type)).getWidth() ==
515 mlir::cast<cir::IntType>(cgf.convertType(
type)).getWidth()) &&
516 "The following check expects that if we do promotion to different "
517 "underlying canonical type, at least one of the types (either "
518 "base or promoted) will be signed, or the bitwidths will match.");
523 value = emitIncDecConsiderOverflowBehavior(e, value, kind);
525 cir::UnaryOpKind
kind =
526 e->
isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;
528 value = emitUnaryOp(e, kind, input,
false);
530 }
else if (
const PointerType *ptr =
type->getAs<PointerType>()) {
531 QualType
type = ptr->getPointeeType();
532 if (cgf.getContext().getAsVariableArrayType(
type)) {
534 cgf.cgm.errorNYI(e->
getSourceRange(),
"Pointer arithmetic on VLA");
536 }
else if (
type->isFunctionType()) {
539 "Pointer arithmetic on function pointer");
544 CIRGenBuilderTy &builder = cgf.getBuilder();
545 int amount =
kind == cir::UnaryOpKind::Inc ? 1 : -1;
546 mlir::Value amt = builder.getSInt32(amount, loc);
548 value = builder.createPtrStride(loc, value, amt);
550 }
else if (
type->isVectorType()) {
553 }
else if (
type->isRealFloatingType()) {
556 if (
type->isHalfType() &&
557 !cgf.getContext().getLangOpts().NativeHalfType) {
562 if (mlir::isa<cir::SingleType, cir::DoubleType>(value.getType())) {
565 assert(kind == cir::UnaryOpKind::Inc ||
566 kind == cir::UnaryOpKind::Dec &&
"Invalid UnaryOp kind");
567 value = emitUnaryOp(e, kind, value);
569 cgf.cgm.errorNYI(e->
getSourceRange(),
"Unary inc/dec other fp type");
572 }
else if (
type->isFixedPointType()) {
573 cgf.cgm.errorNYI(e->
getSourceRange(),
"Unary inc/dec other fixed point");
576 assert(
type->castAs<ObjCObjectPointerType>());
577 cgf.cgm.errorNYI(e->
getSourceRange(),
"Unary inc/dec ObjectiveC pointer");
581 CIRGenFunction::SourceLocRAIIObject sourceloc{
586 return cgf.emitStoreThroughBitfieldLValue(
RValue::get(value), lv);
588 cgf.emitStoreThroughLValue(
RValue::get(value), lv);
592 return isPre ? value : input;
595 mlir::Value emitIncDecConsiderOverflowBehavior(
const UnaryOperator *e,
597 cir::UnaryOpKind kind) {
598 assert(kind == cir::UnaryOpKind::Inc ||
599 kind == cir::UnaryOpKind::Dec &&
"Invalid UnaryOp kind");
600 switch (cgf.getLangOpts().getSignedOverflowBehavior()) {
601 case LangOptions::SOB_Defined:
602 return emitUnaryOp(e, kind, inVal,
false);
603 case LangOptions::SOB_Undefined:
605 return emitUnaryOp(e, kind, inVal,
true);
606 case LangOptions::SOB_Trapping:
608 return emitUnaryOp(e, kind, inVal,
true);
609 cgf.cgm.errorNYI(e->
getSourceRange(),
"inc/def overflow SOB_Trapping");
612 llvm_unreachable(
"Unexpected signed overflow behavior kind");
615 mlir::Value VisitUnaryAddrOf(
const UnaryOperator *e) {
616 if (llvm::isa<MemberPointerType>(e->
getType())) {
617 cgf.cgm.errorNYI(e->
getSourceRange(),
"Address of member pointer");
618 return builder.getNullPtr(cgf.convertType(e->
getType()),
622 return cgf.emitLValue(e->
getSubExpr()).getPointer();
625 mlir::Value VisitUnaryDeref(
const UnaryOperator *e) {
628 return emitLoadOfLValue(e);
631 mlir::Value VisitUnaryPlus(
const UnaryOperator *e) {
634 emitUnaryPlusOrMinus(e, cir::UnaryOpKind::Plus, promotionType);
635 if (result && !promotionType.
isNull())
636 return emitUnPromotedValue(result, e->
getType());
640 mlir::Value VisitUnaryMinus(
const UnaryOperator *e) {
643 emitUnaryPlusOrMinus(e, cir::UnaryOpKind::Minus, promotionType);
644 if (result && !promotionType.
isNull())
645 return emitUnPromotedValue(result, e->
getType());
649 mlir::Value emitUnaryPlusOrMinus(
const UnaryOperator *e,
650 cir::UnaryOpKind kind,
651 QualType promotionType) {
652 ignoreResultAssign =
false;
654 if (!promotionType.
isNull())
655 operand = cgf.emitPromotedScalarExpr(e->
getSubExpr(), promotionType);
664 return emitUnaryOp(e, kind, operand, nsw);
667 mlir::Value emitUnaryOp(
const UnaryOperator *e, cir::UnaryOpKind kind,
668 mlir::Value input,
bool nsw =
false) {
669 return cir::UnaryOp::create(builder,
671 input.getType(), kind, input, nsw);
674 mlir::Value VisitUnaryNot(
const UnaryOperator *e) {
675 ignoreResultAssign =
false;
677 return emitUnaryOp(e, cir::UnaryOpKind::Not, op);
680 mlir::Value VisitUnaryLNot(
const UnaryOperator *e);
682 mlir::Value VisitUnaryReal(
const UnaryOperator *e);
683 mlir::Value VisitUnaryImag(
const UnaryOperator *e);
684 mlir::Value VisitRealImag(
const UnaryOperator *e,
685 QualType promotionType = QualType());
687 mlir::Value VisitUnaryExtension(
const UnaryOperator *e) {
691 mlir::Value VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
692 CIRGenFunction::CXXDefaultInitExprScope scope(cgf, die);
696 mlir::Value VisitCXXThisExpr(CXXThisExpr *te) {
return cgf.loadCXXThis(); }
698 mlir::Value VisitExprWithCleanups(ExprWithCleanups *e);
699 mlir::Value VisitCXXNewExpr(
const CXXNewExpr *e) {
700 return cgf.emitCXXNewExpr(e);
702 mlir::Value VisitCXXDeleteExpr(
const CXXDeleteExpr *e) {
703 cgf.emitCXXDeleteExpr(e);
707 mlir::Value VisitCXXThrowExpr(
const CXXThrowExpr *e) {
708 cgf.emitCXXThrowExpr(e);
717 emitScalarConversion(mlir::Value src, QualType srcType, QualType dstType,
719 ScalarConversionOpts opts = ScalarConversionOpts()) {
729 cgf.getCIRGenModule().errorNYI(loc,
"fixed point conversions");
735 if (srcType == dstType) {
736 if (opts.emitImplicitIntegerSignChangeChecks)
737 cgf.getCIRGenModule().errorNYI(loc,
738 "implicit integer sign change checks");
745 mlir::Type mlirSrcType = src.getType();
750 return emitConversionToBool(src, srcType, cgf.getLoc(loc));
752 mlir::Type mlirDstType = cgf.convertType(dstType);
755 !cgf.getContext().getLangOpts().NativeHalfType) {
757 if (mlir::isa<cir::FPTypeInterface>(mlirDstType)) {
758 if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics())
759 cgf.getCIRGenModule().errorNYI(loc,
760 "cast via llvm.convert.from.fp16");
765 if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics())
766 cgf.getCIRGenModule().errorNYI(loc,
767 "cast via llvm.convert.from.fp16");
770 src = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, src,
772 srcType = cgf.getContext().FloatTy;
773 mlirSrcType = cgf.floatTy;
779 if (mlirSrcType == mlirDstType) {
780 if (opts.emitImplicitIntegerSignChangeChecks)
781 cgf.getCIRGenModule().errorNYI(loc,
782 "implicit integer sign change checks");
789 if (
auto dstPT = dyn_cast<cir::PointerType>(mlirDstType)) {
790 cgf.getCIRGenModule().errorNYI(loc,
"pointer casts");
791 return builder.getNullPtr(dstPT, src.getLoc());
797 return builder.createPtrToInt(src, mlirDstType);
804 assert(dstType->
castAs<ExtVectorType>()->getElementType().getTypePtr() ==
806 "Splatted expr doesn't match with vector element type?");
808 cgf.getCIRGenModule().errorNYI(loc,
"vector splatting");
813 cgf.getCIRGenModule().errorNYI(loc,
814 "matrix type to matrix type conversion");
818 "Internal error: conversion between matrix type and scalar type");
821 mlir::Value res =
nullptr;
822 mlir::Type resTy = mlirDstType;
824 res = emitScalarCast(src, srcType, dstType, mlirSrcType, mlirDstType, opts);
826 if (mlirDstType != resTy) {
827 if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
828 cgf.getCIRGenModule().errorNYI(loc,
"cast via llvm.convert.to.fp16");
832 res = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, res,
836 if (opts.emitImplicitIntegerTruncationChecks)
837 cgf.getCIRGenModule().errorNYI(loc,
"implicit integer truncation checks");
839 if (opts.emitImplicitIntegerSignChangeChecks)
840 cgf.getCIRGenModule().errorNYI(loc,
841 "implicit integer sign change checks");
846 BinOpInfo emitBinOps(
const BinaryOperator *e,
847 QualType promotionType = QualType()) {
848 ignoreResultAssign =
false;
850 result.lhs = cgf.emitPromotedScalarExpr(e->
getLHS(), promotionType);
851 result.rhs = cgf.emitPromotedScalarExpr(e->
getRHS(), promotionType);
852 if (!promotionType.
isNull())
853 result.fullType = promotionType;
855 result.fullType = e->
getType();
856 result.compType = result.fullType;
857 if (
const auto *vecType = dyn_cast_or_null<VectorType>(result.fullType)) {
858 result.compType = vecType->getElementType();
868 mlir::Value emitMul(
const BinOpInfo &ops);
869 mlir::Value emitDiv(
const BinOpInfo &ops);
870 mlir::Value emitRem(
const BinOpInfo &ops);
871 mlir::Value emitAdd(
const BinOpInfo &ops);
872 mlir::Value emitSub(
const BinOpInfo &ops);
873 mlir::Value emitShl(
const BinOpInfo &ops);
874 mlir::Value emitShr(
const BinOpInfo &ops);
875 mlir::Value emitAnd(
const BinOpInfo &ops);
876 mlir::Value emitXor(
const BinOpInfo &ops);
877 mlir::Value emitOr(
const BinOpInfo &ops);
879 LValue emitCompoundAssignLValue(
880 const CompoundAssignOperator *e,
881 mlir::Value (ScalarExprEmitter::*f)(
const BinOpInfo &),
882 mlir::Value &result);
884 emitCompoundAssign(
const CompoundAssignOperator *e,
885 mlir::Value (ScalarExprEmitter::*f)(
const BinOpInfo &));
889 QualType getPromotionType(QualType ty) {
890 const clang::ASTContext &ctx = cgf.getContext();
891 if (
auto *complexTy = ty->
getAs<ComplexType>()) {
892 QualType elementTy = complexTy->getElementType();
898 if (
auto *vt = ty->
getAs<VectorType>()) {
899 unsigned numElements = vt->getNumElements();
902 return cgf.getContext().FloatTy;
909#define HANDLEBINOP(OP) \
910 mlir::Value VisitBin##OP(const BinaryOperator *e) { \
911 QualType promotionTy = getPromotionType(e->getType()); \
912 auto result = emit##OP(emitBinOps(e, promotionTy)); \
913 if (result && !promotionTy.isNull()) \
914 result = emitUnPromotedValue(result, e->getType()); \
917 mlir::Value VisitBin##OP##Assign(const CompoundAssignOperator *e) { \
918 return emitCompoundAssign(e, &ScalarExprEmitter::emit##OP); \
934 ignoreResultAssign =
false;
940 auto clangCmpToCIRCmp =
944 return cir::CmpOpKind::lt;
946 return cir::CmpOpKind::gt;
948 return cir::CmpOpKind::le;
950 return cir::CmpOpKind::ge;
952 return cir::CmpOpKind::eq;
954 return cir::CmpOpKind::ne;
956 llvm_unreachable(
"unsupported comparison kind for cir.cmp");
960 cir::CmpOpKind kind = clangCmpToCIRCmp(e->
getOpcode());
968 BinOpInfo boInfo = emitBinOps(e);
969 mlir::Value lhs = boInfo.lhs;
970 mlir::Value rhs = boInfo.rhs;
980 result = cir::VecCmpOp::create(builder, cgf.
getLoc(boInfo.loc),
982 boInfo.lhs, boInfo.rhs);
984 }
else if (boInfo.isFixedPointOp()) {
987 result = builder.
getBool(
false, loc);
991 mlir::isa<cir::PointerType>(lhs.getType()) &&
992 mlir::isa<cir::PointerType>(rhs.getType())) {
993 cgf.
cgm.
errorNYI(loc,
"strict vtable pointer comparisons");
996 cir::CmpOpKind kind = clangCmpToCIRCmp(e->
getOpcode());
1003 BinOpInfo boInfo = emitBinOps(e);
1004 result = cir::CmpOp::create(builder, loc, kind, boInfo.lhs, boInfo.rhs);
1012#define VISITCOMP(CODE) \
1013 mlir::Value VisitBin##CODE(const BinaryOperator *E) { return emitCmp(E); }
1023 const bool ignore = std::exchange(ignoreResultAssign,
false);
1038 rhs = Visit(e->
getRHS());
1048 if (lhs.isBitField()) {
1068 if (!lhs.isVolatile())
1072 return emitLoadOfLValue(lhs, e->
getExprLoc());
1075 mlir::Value VisitBinComma(
const BinaryOperator *e) {
1076 cgf.emitIgnoredExpr(e->
getLHS());
1078 return Visit(e->
getRHS());
1081 mlir::Value VisitBinLAnd(
const clang::BinaryOperator *e) {
1083 mlir::Location loc = cgf.getLoc(e->
getExprLoc());
1084 auto vecTy = mlir::cast<cir::VectorType>(cgf.convertType(e->
getType()));
1085 mlir::Value zeroValue = builder.getNullValue(vecTy.getElementType(), loc);
1086 SmallVector<mlir::Value, 16> elements(vecTy.getSize(), zeroValue);
1087 auto zeroVec = cir::VecCreateOp::create(builder, loc, vecTy, elements);
1089 mlir::Value lhs = Visit(e->
getLHS());
1090 mlir::Value rhs = Visit(e->
getRHS());
1092 auto cmpOpKind = cir::CmpOpKind::ne;
1093 lhs = cir::VecCmpOp::create(builder, loc, vecTy, cmpOpKind, lhs, zeroVec);
1094 rhs = cir::VecCmpOp::create(builder, loc, vecTy, cmpOpKind, rhs, zeroVec);
1095 mlir::Value vecOr = builder.createAnd(loc, lhs, rhs);
1096 return builder.createIntCast(vecOr, vecTy);
1100 mlir::Type resTy = cgf.convertType(e->
getType());
1101 mlir::Location loc = cgf.getLoc(e->
getExprLoc());
1103 CIRGenFunction::ConditionalEvaluation eval(cgf);
1105 mlir::Value lhsCondV = cgf.evaluateExprAsBool(e->
getLHS());
1106 auto resOp = cir::TernaryOp::create(
1107 builder, loc, lhsCondV,
1108 [&](mlir::OpBuilder &
b, mlir::Location loc) {
1109 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1110 b.getInsertionBlock()};
1111 cgf.curLexScope->setAsTernary();
1112 mlir::Value res = cgf.evaluateExprAsBool(e->
getRHS());
1114 cir::YieldOp::create(
b, loc, res);
1117 [&](mlir::OpBuilder &
b, mlir::Location loc) {
1118 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1119 b.getInsertionBlock()};
1121 auto res = cir::ConstantOp::create(
b, loc, builder.getFalseAttr());
1122 cir::YieldOp::create(
b, loc, res.getRes());
1124 return maybePromoteBoolResult(resOp.getResult(), resTy);
1127 mlir::Value VisitBinLOr(
const clang::BinaryOperator *e) {
1129 mlir::Location loc = cgf.getLoc(e->
getExprLoc());
1130 auto vecTy = mlir::cast<cir::VectorType>(cgf.convertType(e->
getType()));
1131 mlir::Value zeroValue = builder.getNullValue(vecTy.getElementType(), loc);
1132 SmallVector<mlir::Value, 16> elements(vecTy.getSize(), zeroValue);
1133 auto zeroVec = cir::VecCreateOp::create(builder, loc, vecTy, elements);
1135 mlir::Value lhs = Visit(e->
getLHS());
1136 mlir::Value rhs = Visit(e->
getRHS());
1138 auto cmpOpKind = cir::CmpOpKind::ne;
1139 lhs = cir::VecCmpOp::create(builder, loc, vecTy, cmpOpKind, lhs, zeroVec);
1140 rhs = cir::VecCmpOp::create(builder, loc, vecTy, cmpOpKind, rhs, zeroVec);
1141 mlir::Value vecOr = builder.createOr(loc, lhs, rhs);
1142 return builder.createIntCast(vecOr, vecTy);
1146 mlir::Type resTy = cgf.convertType(e->
getType());
1147 mlir::Location loc = cgf.getLoc(e->
getExprLoc());
1149 CIRGenFunction::ConditionalEvaluation eval(cgf);
1151 mlir::Value lhsCondV = cgf.evaluateExprAsBool(e->
getLHS());
1152 auto resOp = cir::TernaryOp::create(
1153 builder, loc, lhsCondV,
1154 [&](mlir::OpBuilder &
b, mlir::Location loc) {
1155 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1156 b.getInsertionBlock()};
1158 auto res = cir::ConstantOp::create(
b, loc, builder.getTrueAttr());
1159 cir::YieldOp::create(
b, loc, res.getRes());
1162 [&](mlir::OpBuilder &
b, mlir::Location loc) {
1163 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1164 b.getInsertionBlock()};
1166 mlir::Value res = cgf.evaluateExprAsBool(e->
getRHS());
1168 cir::YieldOp::create(
b, loc, res);
1171 return maybePromoteBoolResult(resOp.getResult(), resTy);
1174 mlir::Value VisitAtomicExpr(AtomicExpr *e) {
1175 return cgf.emitAtomicExpr(e).getValue();
1179LValue ScalarExprEmitter::emitCompoundAssignLValue(
1181 mlir::Value (ScalarExprEmitter::*func)(
const BinOpInfo &),
1182 mlir::Value &result) {
1193 if (promotionTypeCR.
isNull())
1197 QualType promotionTypeRHS = getPromotionType(e->
getRHS()->
getType());
1199 if (!promotionTypeRHS.
isNull())
1202 opInfo.rhs = Visit(e->
getRHS());
1204 opInfo.fullType = promotionTypeCR;
1205 opInfo.compType = opInfo.fullType;
1206 if (
const auto *vecType = dyn_cast_or_null<VectorType>(opInfo.fullType))
1207 opInfo.compType = vecType->getElementType();
1216 if (lhsTy->
getAs<AtomicType>()) {
1217 cgf.
cgm.
errorNYI(result.getLoc(),
"atomic lvalue assign");
1221 opInfo.lhs = emitLoadOfLValue(lhsLV, e->
getExprLoc());
1223 CIRGenFunction::SourceLocRAIIObject sourceloc{
1226 if (!promotionTypeLHS.
isNull())
1227 opInfo.lhs = emitScalarConversion(opInfo.lhs, lhsTy, promotionTypeLHS, loc);
1229 opInfo.lhs = emitScalarConversion(opInfo.lhs, lhsTy,
1233 result = (this->*func)(opInfo);
1237 result = emitScalarConversion(result, promotionTypeCR, lhsTy, loc,
1238 ScalarConversionOpts(cgf.
sanOpts));
1244 if (lhsLV.isBitField())
1255mlir::Value ScalarExprEmitter::emitComplexToScalarConversion(mlir::Location lov,
1259 cir::CastKind castOpKind;
1261 case CK_FloatingComplexToReal:
1262 castOpKind = cir::CastKind::float_complex_to_real;
1264 case CK_IntegralComplexToReal:
1265 castOpKind = cir::CastKind::int_complex_to_real;
1267 case CK_FloatingComplexToBoolean:
1268 castOpKind = cir::CastKind::float_complex_to_bool;
1270 case CK_IntegralComplexToBoolean:
1271 castOpKind = cir::CastKind::int_complex_to_bool;
1274 llvm_unreachable(
"invalid complex-to-scalar cast kind");
1280mlir::Value ScalarExprEmitter::emitPromoted(
const Expr *e,
1281 QualType promotionType) {
1283 if (
const auto *bo = dyn_cast<BinaryOperator>(e)) {
1284 switch (bo->getOpcode()) {
1285#define HANDLE_BINOP(OP) \
1287 return emit##OP(emitBinOps(bo, promotionType));
1296 }
else if (
const auto *uo = dyn_cast<UnaryOperator>(e)) {
1297 switch (uo->getOpcode()) {
1300 return VisitRealImag(uo, promotionType);
1302 return emitUnaryPlusOrMinus(uo, cir::UnaryOpKind::Minus, promotionType);
1304 return emitUnaryPlusOrMinus(uo, cir::UnaryOpKind::Plus, promotionType);
1309 mlir::Value result = Visit(
const_cast<Expr *
>(e));
1311 if (!promotionType.
isNull())
1312 return emitPromotedValue(result, promotionType);
1313 return emitUnPromotedValue(result, e->
getType());
1318mlir::Value ScalarExprEmitter::emitCompoundAssign(
1319 const CompoundAssignOperator *e,
1320 mlir::Value (ScalarExprEmitter::*func)(
const BinOpInfo &)) {
1322 bool ignore = std::exchange(ignoreResultAssign,
false);
1324 LValue lhs = emitCompoundAssignLValue(e, func, rhs);
1335 if (!lhs.isVolatile())
1339 return emitLoadOfLValue(lhs, e->
getExprLoc());
1342mlir::Value ScalarExprEmitter::VisitExprWithCleanups(ExprWithCleanups *e) {
1344 mlir::OpBuilder &builder = cgf.builder;
1346 auto scope = cir::ScopeOp::create(
1349 [&](mlir::OpBuilder &
b, mlir::Type &yieldTy, mlir::Location loc) {
1350 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1351 builder.getInsertionBlock()};
1352 mlir::Value scopeYieldVal = Visit(e->
getSubExpr());
1353 if (scopeYieldVal) {
1357 cir::YieldOp::create(builder, loc, scopeYieldVal);
1358 yieldTy = scopeYieldVal.getType();
1362 return scope.getNumResults() > 0 ? scope->getResult(0) :
nullptr;
1372#define COMPOUND_OP(Op) \
1373 case BO_##Op##Assign: \
1374 return emitter.emitCompoundAssignLValue(e, &ScalarExprEmitter::emit##Op, \
1411 llvm_unreachable(
"Not valid compound assignment operators");
1413 llvm_unreachable(
"Unhandled compound assignment operator");
1418 bool ignoreResultAssign) {
1420 "Invalid scalar expression to emit");
1423 .Visit(
const_cast<Expr *
>(e));
1428 if (!promotionType.
isNull())
1443static std::optional<QualType>
1447 return std::nullopt;
1452 return std::nullopt;
1465 const BinOpInfo &op) {
1467 "Expected a unary or binary operator");
1471 if (!op.mayHaveIntegerOverflow())
1475 if (
const auto *uo = dyn_cast<UnaryOperator>(op.e))
1476 return !uo->canOverflow();
1481 std::optional<QualType> optionalLHSTy =
1486 std::optional<QualType> optionalRHSTy =
1496 if ((op.opcode != BO_Mul && op.opcode != BO_MulAssign) ||
1503 return (2 * astContext.
getTypeSize(lhsTy)) < promotedSize ||
1504 (2 * astContext.
getTypeSize(rhsTy)) < promotedSize;
1509 const BinOpInfo &op,
1510 bool isSubtraction) {
1515 mlir::Value pointer = op.lhs;
1516 Expr *pointerOperand =
expr->getLHS();
1517 mlir::Value
index = op.rhs;
1518 Expr *indexOperand =
expr->getRHS();
1524 if (!isSubtraction && !mlir::isa<cir::PointerType>(pointer.getType())) {
1525 std::swap(pointer,
index);
1526 std::swap(pointerOperand, indexOperand);
1528 assert(mlir::isa<cir::PointerType>(pointer.getType()) &&
1529 "Need a pointer operand");
1530 assert(mlir::isa<cir::IntType>(
index.getType()) &&
"Need an integer operand");
1565 cgf.
cgm.
errorNYI(
"Objective-C:pointer arithmetic with non-pointer type");
1576 cgf.
cgm.
errorNYI(
"void* or function pointer arithmetic");
1581 return cir::PtrStrideOp::create(cgf.
getBuilder(),
1583 pointer.getType(), pointer,
index);
1586mlir::Value ScalarExprEmitter::emitMul(
const BinOpInfo &ops) {
1587 const mlir::Location loc = cgf.
getLoc(ops.loc);
1589 switch (cgf.
getLangOpts().getSignedOverflowBehavior()) {
1590 case LangOptions::SOB_Defined:
1591 if (!cgf.
sanOpts.
has(SanitizerKind::SignedIntegerOverflow))
1592 return builder.createMul(loc, ops.lhs, ops.rhs);
1594 case LangOptions::SOB_Undefined:
1595 if (!cgf.
sanOpts.
has(SanitizerKind::SignedIntegerOverflow))
1596 return builder.createNSWMul(loc, ops.lhs, ops.rhs);
1598 case LangOptions::SOB_Trapping:
1600 return builder.createNSWMul(loc, ops.lhs, ops.rhs);
1610 cgf.
sanOpts.
has(SanitizerKind::UnsignedIntegerOverflow) &&
1612 cgf.
cgm.
errorNYI(
"unsigned int overflow sanitizer");
1614 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
1616 return builder.createFMul(loc, ops.lhs, ops.rhs);
1619 if (ops.isFixedPointOp()) {
1625 return cir::BinOp::create(builder, cgf.
getLoc(ops.loc),
1626 cgf.
convertType(ops.fullType), cir::BinOpKind::Mul,
1629mlir::Value ScalarExprEmitter::emitDiv(
const BinOpInfo &ops) {
1630 return cir::BinOp::create(builder, cgf.
getLoc(ops.loc),
1631 cgf.
convertType(ops.fullType), cir::BinOpKind::Div,
1634mlir::Value ScalarExprEmitter::emitRem(
const BinOpInfo &ops) {
1635 return cir::BinOp::create(builder, cgf.
getLoc(ops.loc),
1636 cgf.
convertType(ops.fullType), cir::BinOpKind::Rem,
1640mlir::Value ScalarExprEmitter::emitAdd(
const BinOpInfo &ops) {
1641 if (mlir::isa<cir::PointerType>(ops.lhs.getType()) ||
1642 mlir::isa<cir::PointerType>(ops.rhs.getType()))
1645 const mlir::Location loc = cgf.
getLoc(ops.loc);
1647 switch (cgf.
getLangOpts().getSignedOverflowBehavior()) {
1648 case LangOptions::SOB_Defined:
1649 if (!cgf.
sanOpts.
has(SanitizerKind::SignedIntegerOverflow))
1650 return builder.createAdd(loc, ops.lhs, ops.rhs);
1652 case LangOptions::SOB_Undefined:
1653 if (!cgf.
sanOpts.
has(SanitizerKind::SignedIntegerOverflow))
1654 return builder.createNSWAdd(loc, ops.lhs, ops.rhs);
1656 case LangOptions::SOB_Trapping:
1658 return builder.createNSWAdd(loc, ops.lhs, ops.rhs);
1669 cgf.
sanOpts.
has(SanitizerKind::UnsignedIntegerOverflow) &&
1671 cgf.
cgm.
errorNYI(
"unsigned int overflow sanitizer");
1673 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
1675 return builder.createFAdd(loc, ops.lhs, ops.rhs);
1678 if (ops.isFixedPointOp()) {
1684 return cir::BinOp::create(builder, loc, cgf.
convertType(ops.fullType),
1685 cir::BinOpKind::Add, ops.lhs, ops.rhs);
1688mlir::Value ScalarExprEmitter::emitSub(
const BinOpInfo &ops) {
1689 const mlir::Location loc = cgf.
getLoc(ops.loc);
1691 if (!mlir::isa<cir::PointerType>(ops.lhs.getType())) {
1693 switch (cgf.
getLangOpts().getSignedOverflowBehavior()) {
1694 case LangOptions::SOB_Defined: {
1695 if (!cgf.
sanOpts.
has(SanitizerKind::SignedIntegerOverflow))
1696 return builder.createSub(loc, ops.lhs, ops.rhs);
1699 case LangOptions::SOB_Undefined:
1700 if (!cgf.
sanOpts.
has(SanitizerKind::SignedIntegerOverflow))
1701 return builder.createNSWSub(loc, ops.lhs, ops.rhs);
1703 case LangOptions::SOB_Trapping:
1705 return builder.createNSWSub(loc, ops.lhs, ops.rhs);
1717 cgf.
sanOpts.
has(SanitizerKind::UnsignedIntegerOverflow) &&
1719 cgf.
cgm.
errorNYI(
"unsigned int overflow sanitizer");
1721 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
1723 return builder.createFSub(loc, ops.lhs, ops.rhs);
1726 if (ops.isFixedPointOp()) {
1732 return cir::BinOp::create(builder, cgf.
getLoc(ops.loc),
1734 cir::BinOpKind::Sub, ops.lhs, ops.rhs);
1739 if (!mlir::isa<cir::PointerType>(ops.rhs.getType()))
1751 return cir::PtrDiffOp::create(builder, cgf.
getLoc(ops.loc), cgf.
ptrDiffTy,
1755mlir::Value ScalarExprEmitter::emitShl(
const BinOpInfo &ops) {
1757 if (ops.isFixedPointOp()) {
1767 bool sanitizeSignedBase = cgf.
sanOpts.
has(SanitizerKind::ShiftBase) &&
1771 bool sanitizeUnsignedBase =
1772 cgf.
sanOpts.
has(SanitizerKind::UnsignedShiftBase) &&
1774 bool sanitizeBase = sanitizeSignedBase || sanitizeUnsignedBase;
1775 bool sanitizeExponent = cgf.
sanOpts.
has(SanitizerKind::ShiftExponent);
1780 else if ((sanitizeBase || sanitizeExponent) &&
1781 mlir::isa<cir::IntType>(ops.lhs.getType()))
1784 return builder.createShiftLeft(cgf.
getLoc(ops.loc), ops.lhs, ops.rhs);
1787mlir::Value ScalarExprEmitter::emitShr(
const BinOpInfo &ops) {
1789 if (ops.isFixedPointOp()) {
1802 else if (cgf.
sanOpts.
has(SanitizerKind::ShiftExponent) &&
1803 mlir::isa<cir::IntType>(ops.lhs.getType()))
1808 return builder.createShiftRight(cgf.
getLoc(ops.loc), ops.lhs, ops.rhs);
1811mlir::Value ScalarExprEmitter::emitAnd(
const BinOpInfo &ops) {
1812 return cir::BinOp::create(builder, cgf.
getLoc(ops.loc),
1813 cgf.
convertType(ops.fullType), cir::BinOpKind::And,
1816mlir::Value ScalarExprEmitter::emitXor(
const BinOpInfo &ops) {
1817 return cir::BinOp::create(builder, cgf.
getLoc(ops.loc),
1818 cgf.
convertType(ops.fullType), cir::BinOpKind::Xor,
1821mlir::Value ScalarExprEmitter::emitOr(
const BinOpInfo &ops) {
1822 return cir::BinOp::create(builder, cgf.
getLoc(ops.loc),
1823 cgf.
convertType(ops.fullType), cir::BinOpKind::Or,
1831mlir::Value ScalarExprEmitter::VisitCastExpr(
CastExpr *ce) {
1833 QualType destTy = ce->
getType();
1838 ignoreResultAssign =
false;
1841 case clang::CK_Dependent:
1842 llvm_unreachable(
"dependent cast kind in CIR gen!");
1843 case clang::CK_BuiltinFnToFnPtr:
1844 llvm_unreachable(
"builtin functions are handled elsewhere");
1846 case CK_CPointerToObjCPointerCast:
1847 case CK_BlockPointerToObjCPointerCast:
1848 case CK_AnyPointerToBlockPointerCast:
1850 mlir::Value src = Visit(
const_cast<Expr *
>(subExpr));
1855 if (cgf.
sanOpts.
has(SanitizerKind::CFIUnrelatedCast))
1857 "sanitizer support");
1861 "strict vtable pointers");
1888 case CK_AtomicToNonAtomic: {
1894 case CK_NonAtomicToAtomic:
1895 case CK_UserDefinedConversion:
1896 return Visit(
const_cast<Expr *
>(subExpr));
1898 auto v = Visit(
const_cast<Expr *
>(subExpr));
1904 if (t != v.getType())
1909 case CK_IntegralToPointer: {
1911 mlir::Value src = Visit(
const_cast<Expr *
>(subExpr));
1918 mlir::Value middleVal = builder.createCast(
1920 : cir::CastKind::integral,
1925 "IntegralToPointer: strict vtable pointers");
1929 return builder.createIntToPtr(middleVal, destCIRTy);
1937 case CK_ArrayToPointerDecay:
1940 case CK_NullToPointer: {
1950 case CK_LValueToRValue:
1952 assert(subExpr->
isGLValue() &&
"lvalue-to-rvalue applied to r-value!");
1953 return Visit(
const_cast<Expr *
>(subExpr));
1955 case CK_IntegralCast: {
1956 ScalarConversionOpts opts;
1957 if (
auto *ice = dyn_cast<ImplicitCastExpr>(ce)) {
1958 if (!ice->isPartOfExplicitCast())
1959 opts = ScalarConversionOpts(cgf.
sanOpts);
1961 return emitScalarConversion(Visit(subExpr), subExpr->
getType(), destTy,
1965 case CK_FloatingComplexToReal:
1966 case CK_IntegralComplexToReal:
1967 case CK_FloatingComplexToBoolean:
1968 case CK_IntegralComplexToBoolean: {
1974 case CK_FloatingRealToComplex:
1975 case CK_FloatingComplexCast:
1976 case CK_IntegralRealToComplex:
1977 case CK_IntegralComplexCast:
1978 case CK_IntegralComplexToFloatingComplex:
1979 case CK_FloatingComplexToIntegralComplex:
1980 llvm_unreachable(
"scalar cast to non-scalar value");
1982 case CK_PointerToIntegral: {
1983 assert(!destTy->
isBooleanType() &&
"bool should use PointerToBool");
1986 "strict vtable pointers");
1987 return builder.createPtrToInt(Visit(subExpr), cgf.
convertType(destTy));
1993 case CK_IntegralToFloating:
1994 case CK_FloatingToIntegral:
1995 case CK_FloatingCast:
1996 case CK_FixedPointToFloating:
1997 case CK_FloatingToFixedPoint: {
1998 if (kind == CK_FixedPointToFloating || kind == CK_FloatingToFixedPoint) {
2000 "fixed point casts");
2004 return emitScalarConversion(Visit(subExpr), subExpr->
getType(), destTy,
2008 case CK_IntegralToBoolean:
2009 return emitIntToBoolConversion(Visit(subExpr),
2012 case CK_PointerToBoolean:
2013 return emitPointerToBoolConversion(Visit(subExpr), subExpr->
getType());
2014 case CK_FloatingToBoolean:
2015 return emitFloatToBoolConversion(Visit(subExpr),
2017 case CK_MemberPointerToBoolean: {
2018 mlir::Value memPtr = Visit(subExpr);
2020 cir::CastKind::member_ptr_to_bool, memPtr,
2024 case CK_VectorSplat: {
2026 assert(destTy->
isVectorType() &&
"CK_VectorSplat to non-vector type");
2027 return cir::VecSplatOp::create(builder,
2031 case CK_FunctionToPointerDecay:
2041mlir::Value ScalarExprEmitter::VisitCallExpr(
const CallExpr *e) {
2043 return emitLoadOfLValue(e);
2050mlir::Value ScalarExprEmitter::VisitMemberExpr(MemberExpr *e) {
2055 Expr::EvalResult result;
2057 llvm::APSInt value = result.
Val.
getInt();
2061 return emitLoadOfLValue(e);
2064mlir::Value ScalarExprEmitter::VisitInitListExpr(InitListExpr *e) {
2065 const unsigned numInitElements = e->
getNumInits();
2067 [[maybe_unused]]
const bool ignore = std::exchange(ignoreResultAssign,
false);
2068 assert((ignore ==
false ||
2070 "init list ignored");
2078 const auto vectorType =
2081 SmallVector<mlir::Value, 16> elements;
2082 for (Expr *init : e->
inits()) {
2083 elements.push_back(Visit(init));
2087 if (numInitElements < vectorType.getSize()) {
2090 std::fill_n(std::back_inserter(elements),
2091 vectorType.getSize() - numInitElements, zeroValue);
2094 return cir::VecCreateOp::create(cgf.
getBuilder(),
2100 if (numInitElements == 0)
2111 "Invalid scalar expression to emit");
2113 .emitScalarConversion(src, srcTy, dstTy, loc);
2121 "Invalid complex -> scalar conversion");
2126 ? cir::CastKind::float_complex_to_bool
2127 : cir::CastKind::int_complex_to_bool;
2132 ? cir::CastKind::float_complex_to_real
2133 : cir::CastKind::int_complex_to_real;
2139mlir::Value ScalarExprEmitter::VisitUnaryLNot(
const UnaryOperator *e) {
2146 auto operVecTy = mlir::cast<cir::VectorType>(oper.getType());
2148 mlir::Value zeroVec = builder.getNullValue(operVecTy, loc);
2149 return cir::VecCmpOp::create(builder, loc, exprVecTy, cir::CmpOpKind::eq,
2157 boolVal = builder.createNot(boolVal);
2163mlir::Value ScalarExprEmitter::VisitUnaryReal(
const UnaryOperator *e) {
2165 mlir::Value result = VisitRealImag(e, promotionTy);
2166 if (result && !promotionTy.
isNull())
2167 result = emitUnPromotedValue(result, e->
getType());
2171mlir::Value ScalarExprEmitter::VisitUnaryImag(
const UnaryOperator *e) {
2173 mlir::Value result = VisitRealImag(e, promotionTy);
2174 if (result && !promotionTy.
isNull())
2175 result = emitUnPromotedValue(result, e->
getType());
2179mlir::Value ScalarExprEmitter::VisitRealImag(
const UnaryOperator *e,
2180 QualType promotionTy) {
2181 assert(e->
getOpcode() == clang::UO_Real ||
2183 "Invalid UnaryOp kind for ComplexType Real or Imag");
2200 ? builder.createComplexReal(loc, complex)
2201 : builder.createComplexImag(loc, complex);
2205 mlir::Value operand = promotionTy.
isNull()
2207 : cgf.emitPromotedScalarExpr(op, promotionTy);
2208 return builder.createComplexReal(loc, operand);
2213 mlir::Value operand;
2216 operand = cir::LoadOp::create(builder, loc, operand);
2217 }
else if (!promotionTy.
isNull()) {
2222 return builder.createComplexImag(loc, operand);
2227mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
2228 const UnaryExprOrTypeTraitExpr *e) {
2232 kind == UETT_SizeOf || kind == UETT_DataSizeOf) {
2235 "sizeof operator for VariableArrayType",
2237 return builder.getConstant(
2239 llvm::APSInt(llvm::APInt(64, 1),
true)));
2241 }
else if (e->
getKind() == UETT_OpenMPRequiredSimdAlign) {
2243 e->
getSourceRange(),
"sizeof operator for OpenMpRequiredSimdAlign",
2245 return builder.getConstant(
2247 llvm::APSInt(llvm::APInt(64, 1),
true)));
2250 return builder.getConstant(
2272mlir::Value ScalarExprEmitter::VisitAbstractConditionalOperator(
2273 const AbstractConditionalOperator *e) {
2276 ignoreResultAssign =
false;
2279 CIRGenFunction::OpaqueValueMapping binding(cgf, e);
2281 Expr *condExpr = e->
getCond();
2289 Expr *live = lhsExpr, *dead = rhsExpr;
2291 std::swap(live, dead);
2297 mlir::Value result = Visit(live);
2304 "throw expression in conditional operator");
2312 QualType condType = condExpr->
getType();
2325 cgf.
cgm.
errorNYI(loc,
"TernaryOp for SVE vector");
2329 mlir::Value condValue = Visit(condExpr);
2330 mlir::Value lhsValue = Visit(lhsExpr);
2331 mlir::Value rhsValue = Visit(rhsExpr);
2332 return cir::VecTernaryOp::create(builder, loc, condValue, lhsValue,
2341 bool lhsIsVoid =
false;
2345 mlir::Value lhs = Visit(lhsExpr);
2351 mlir::Value rhs = Visit(rhsExpr);
2353 assert(!rhs &&
"lhs and rhs types must match");
2361 CIRGenFunction::ConditionalEvaluation eval(cgf);
2362 SmallVector<mlir::OpBuilder::InsertPoint, 2> insertPoints{};
2363 mlir::Type yieldTy{};
2365 auto emitBranch = [&](mlir::OpBuilder &
b, mlir::Location loc, Expr *
expr) {
2366 CIRGenFunction::LexicalScope lexScope{cgf, loc,
b.getInsertionBlock()};
2370 eval.beginEvaluation();
2371 mlir::Value branch = Visit(
expr);
2372 eval.endEvaluation();
2375 yieldTy = branch.getType();
2376 cir::YieldOp::create(
b, loc, branch);
2380 insertPoints.push_back(
b.saveInsertionPoint());
2384 mlir::Value result = cir::TernaryOp::create(
2385 builder, loc, condV,
2387 [&](mlir::OpBuilder &
b, mlir::Location loc) {
2388 emitBranch(
b, loc, lhsExpr);
2391 [&](mlir::OpBuilder &
b, mlir::Location loc) {
2392 emitBranch(
b, loc, rhsExpr);
2396 if (!insertPoints.empty()) {
2402 for (mlir::OpBuilder::InsertPoint &toInsert : insertPoints) {
2403 mlir::OpBuilder::InsertionGuard guard(builder);
2404 builder.restoreInsertionPoint(toInsert);
2407 if (mlir::isa<cir::VoidType>(yieldTy)) {
2408 cir::YieldOp::create(builder, loc);
2411 cir::YieldOp::create(builder, loc, op0);
2421 cir::UnaryOpKind kind,
2424 .emitScalarPrePostIncDec(e, lv, kind, isPre);
static bool mustVisitNullValue(const Expr *e)
static bool isWidenedIntegerOp(const ASTContext &astContext, const Expr *e)
Check if e is a widened promoted integer.
static mlir::Value emitPointerArithmetic(CIRGenFunction &cgf, const BinOpInfo &op, bool isSubtraction)
Emit pointer + index arithmetic.
static bool isCheapEnoughToEvaluateUnconditionally(const Expr *e, CIRGenFunction &cgf)
Return true if the specified expression is cheap enough and side-effect-free enough to evaluate uncon...
static bool canElideOverflowCheck(const ASTContext &astContext, const BinOpInfo &op)
Check if we can skip the overflow check for Op.
static std::optional< QualType > getUnwidenedIntegerType(const ASTContext &astContext, const Expr *e)
If e is a widened promoted integer, get its base (unpromoted) type.
__device__ __2f16 float __ockl_bool s
cir::ConstantOp getBool(bool state, mlir::Location loc)
cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc)
mlir::Value createCast(mlir::Location loc, cir::CastKind kind, mlir::Value src, mlir::Type newTy)
mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy)
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
mlir::Value createSelect(mlir::Location loc, mlir::Value condition, mlir::Value trueValue, mlir::Value falseValue)
mlir::Type getIntPtrType(mlir::Type ty) const
llvm::APInt getValue() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
QualType getVectorType(QualType VectorType, unsigned NumElts, VectorKind VecKind) const
Return the unique reference to a vector type of the specified element type and size.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
const VariableArrayType * getAsVariableArrayType(QualType T) const
QualType getComplexType(QualType T) const
Return the uniqued reference to the type for a complex number with the specified element type.
bool isPromotableIntegerType(QualType T) const
More type predicates useful for type checking/promotion.
static bool hasSameUnqualifiedType(QualType T1, QualType T2)
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
Expr * getCond() const
getCond - Return the expression representing the condition for the ?
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
A builtin binary operation expression such as "x + y" or "x <= y".
SourceLocation getExprLoc() const
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const
Get the FP features status of this operator.
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...
BinaryOperatorKind Opcode
mlir::Value getPointer() const
mlir::Value createNeg(mlir::Value value)
void forceCleanup()
Force the emission of cleanups now, instead of waiting until this object is destroyed.
static bool hasScalarEvaluationKind(clang::QualType type)
mlir::Value emitComplexToScalarConversion(mlir::Value src, QualType srcTy, QualType dstTy, SourceLocation loc)
Emit a conversion from the specified complex type to the specified destination type,...
mlir::Type convertType(clang::QualType t)
mlir::Value emitPromotedValue(mlir::Value result, QualType promotionType)
Address emitPointerWithAlignment(const clang::Expr *expr, LValueBaseInfo *baseInfo=nullptr)
Given an expression with a pointer type, emit the value and compute our best estimate of the alignmen...
const clang::LangOptions & getLangOpts() const
LValue emitScalarCompoundAssignWithComplex(const CompoundAssignOperator *e, mlir::Value &result)
mlir::Value emitComplexExpr(const Expr *e)
Emit the computation of the specified expression of complex type, returning the result.
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).
mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv, cir::UnaryOpKind kind, bool isPre)
friend class ::ScalarExprEmitter
mlir::Value emitScalarConversion(mlir::Value src, clang::QualType srcType, clang::QualType dstType, clang::SourceLocation loc)
Emit a conversion from the specified type to the specified destination type, both of which are CIR sc...
clang::SanitizerSet sanOpts
Sanitizers enabled for this function.
mlir::Value createDummyValue(mlir::Location loc, clang::QualType qt)
LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e)
mlir::Value 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)
CIRGenBuilderTy & getBuilder()
CIRGenModule & getCIRGenModule()
bool containsLabel(const clang::Stmt *s, bool ignoreCaseStmts=false)
Return true if the statement contains a label in it.
Address emitArrayToPointerDecay(const Expr *e, LValueBaseInfo *baseInfo=nullptr)
LexicalScope * curLexScope
mlir::Value emitStoreThroughBitfieldLValue(RValue src, LValue dstresult)
clang::ASTContext & getContext() const
void emitNullabilityCheck(LValue lhs, mlir::Value rhs, clang::SourceLocation loc)
Given an assignment *lhs = rhs, emit a test that checks if rhs is nonnull, if 1LHS is marked _Nonnull...
void emitStoreThroughLValue(RValue src, LValue dst, bool isInit=false)
Store the specified rvalue into the specified lvalue, where both are guaranteed to the have the same ...
void emitIgnoredExpr(const clang::Expr *e)
Emit code to compute the specified expression, ignoring the result.
mlir::Value emitDynamicCast(Address thisAddr, const CXXDynamicCastExpr *dce)
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
const cir::CIRDataLayout getDataLayout() const
const clang::CodeGenOptions & getCodeGenOpts() const
mlir::Value getPointer() const
static RValue get(mlir::Value v)
mlir::Value getValue() const
Return the value of this scalar value.
Expr * getExpr()
Get the initialization expression that will be used.
QualType getCallReturnType(const ASTContext &Ctx) const
getCallReturnType - Get the return type of the call expr.
CastKind getCastKind() const
static const char * getCastKindName(CastKind CK)
unsigned getValue() const
Complex values, per C99 6.2.5p11.
CompoundAssignOperator - For compound assignments (e.g.
QualType getComputationLHSType() const
QualType getComputationResultType() const
Expr * getSrcExpr() const
getSrcExpr - Return the Expr to be converted.
This represents one expression.
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,...
@ SE_AllowSideEffects
Allow any unmodeled side effect.
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.
bool isEvaluatable(const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects) const
isEvaluatable - Call EvaluateAsRValue to see if this expression can be constant folded without side-e...
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
llvm::APFloat getValue() const
const Expr * getSubExpr() const
Expr * getResultExpr()
Return the result expression of this controlling expression.
unsigned getNumInits() const
bool hadArrayRangeDesignator() const
const Expr * getInit(unsigned Init) const
ArrayRef< Expr * > inits()
bool isSignedOverflowDefined() const
SourceLocation getExprLoc() const LLVM_READONLY
A pointer to member type per C++ 8.3.3 - Pointers to members.
SourceLocation getExprLoc() const LLVM_READONLY
Expr * getSelectedExpr() const
const Expr * getSubExpr() const
PointerType - C99 6.7.5.1 - Pointer Declarators.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Qualifiers::ObjCLifetime getObjCLifetime() const
Returns lifetime attribute of this type.
QualType getCanonicalType() const
bool UseExcessPrecision(const ASTContext &Ctx)
@ OCL_Strong
Assigning into this object requires the old value to be released and the new value to be retained.
@ OCL_ExplicitNone
This object can be modified without requiring retains or releases.
@ OCL_None
There is no lifetime qualification on this type.
@ OCL_Weak
Reading or writing from this object requires a barrier call.
@ OCL_Autoreleasing
Assigning into this object requires a lifetime extension.
unsigned getNumSubExprs() const
getNumSubExprs - Return the size of the SubExprs array.
Expr * getExpr(unsigned Index)
getExpr - Return the Expr at the specified index.
Encodes a location in the source.
SourceLocation getBegin() const
CompoundStmt * getSubStmt()
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...
const char * getStmtClassName() const
Expr * getReplacement() const
bool isBooleanType() const
bool isSignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
bool isConstantMatrixType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
const T * castAs() const
Member-template castAs<specific type>.
bool isReferenceType() const
bool isSveVLSBuiltinType() const
Determines if this is a sizeless type supported by the 'arm_sve_vector_bits' type attribute,...
bool hasUnsignedIntegerRepresentation() const
Determine whether this type has an unsigned integer representation of some sort, e....
bool isExtVectorType() const
bool isAnyComplexType() const
bool isFixedPointType() const
Return true if this is a fixed point type according to ISO/IEC JTC1 SC22 WG14 N1169.
bool hasSignedIntegerRepresentation() const
Determine whether this type has an signed integer representation of some sort, e.g....
bool isMatrixType() const
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
bool isFunctionType() const
bool isVectorType() const
bool isRealFloatingType() const
Floating point categories.
bool isFloatingType() const
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
const T * getAs() const
Member-template getAs<specific type>'.
bool isNullPtrType() const
QualType getTypeOfArgument() const
Gets the argument type, or the type of the argument expression, whichever is appropriate.
UnaryExprOrTypeTrait getKind() const
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
SourceLocation getExprLoc() const
Expr * getSubExpr() const
static bool isIncrementOp(Opcode Op)
bool canOverflow() const
Returns true if the unary operator can cause an overflow.
Represents a GCC generic vector type.
VectorKind getVectorKind() const
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::ArgumentAdaptingMatcherFunc< internal::HasMatcher > has
Matches AST nodes that have child AST nodes that match the provided matcher.
const AstTypeMatcher< PointerType > pointerType
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
unsigned kind
All of the diagnostics that can be emitted by the frontend.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
CastKind
CastKind - The kind of operation required for a conversion.
@ Generic
not a target-specific vector type
U cast(CodeGen::Address addr)
static bool instrumentation()
static bool dataMemberType()
static bool objCLifetime()
static bool addressSpace()
static bool fixedPointType()
static bool vecTernaryOp()
static bool cgFPOptionsRAII()
static bool fpConstraints()
static bool addHeapAllocSiteMetadata()
static bool mayHaveIntegerOverflow()
static bool tryEmitAsConstant()
static bool llvmLoweringPtrDiffConsidersPointee()
static bool scalableVectors()
static bool emitLValueAlignmentAssumption()
static bool incrementProfileCounter()
APValue Val
Val - This is the value the expression can be folded to.
bool has(SanitizerMask K) const
Check if a certain (single) sanitizer is enabled.