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;
81 bool ignoreResultAssign;
84 ScalarExprEmitter(CIRGenFunction &cgf, CIRGenBuilderTy &builder)
85 : cgf(cgf), builder(builder) {}
91 mlir::Value emitComplexToScalarConversion(mlir::Location loc,
95 mlir::Value emitNullValue(QualType ty, mlir::Location loc) {
96 return cgf.cgm.emitNullConstant(ty, loc);
99 mlir::Value emitPromotedValue(mlir::Value result, QualType promotionType) {
100 return builder.createFloatingCast(result, cgf.convertType(promotionType));
103 mlir::Value emitUnPromotedValue(mlir::Value result, QualType exprType) {
104 return builder.createFloatingCast(result, cgf.convertType(exprType));
107 mlir::Value emitPromoted(
const Expr *e, QualType promotionType);
109 mlir::Value maybePromoteBoolResult(mlir::Value value,
110 mlir::Type dstTy)
const {
111 if (mlir::isa<cir::IntType>(dstTy))
112 return builder.createBoolToInt(value, dstTy);
113 if (mlir::isa<cir::BoolType>(dstTy))
115 llvm_unreachable(
"Can only promote integer or boolean types");
122 mlir::Value Visit(Expr *e) {
123 return StmtVisitor<ScalarExprEmitter, mlir::Value>::Visit(e);
126 mlir::Value VisitStmt(Stmt *
s) {
127 llvm_unreachable(
"Statement passed to ScalarExprEmitter");
130 mlir::Value VisitExpr(Expr *e) {
131 cgf.getCIRGenModule().errorNYI(
136 mlir::Value VisitPackIndexingExpr(PackIndexingExpr *e) {
140 mlir::Value VisitParenExpr(ParenExpr *pe) {
return Visit(pe->
getSubExpr()); }
142 mlir::Value VisitGenericSelectionExpr(GenericSelectionExpr *ge) {
147 mlir::Value emitLoadOfLValue(
const Expr *e) {
148 LValue lv = cgf.emitLValue(e);
150 return cgf.emitLoadOfLValue(lv, e->
getExprLoc()).getValue();
153 mlir::Value emitLoadOfLValue(LValue lv, SourceLocation loc) {
154 return cgf.emitLoadOfLValue(lv, loc).getValue();
158 mlir::Value VisitDeclRefExpr(DeclRefExpr *e) {
159 if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(e))
160 return cgf.emitScalarConstant(constant, e);
162 return emitLoadOfLValue(e);
165 mlir::Value VisitIntegerLiteral(
const IntegerLiteral *e) {
167 return builder.create<cir::ConstantOp>(
171 mlir::Value VisitFloatingLiteral(
const FloatingLiteral *e) {
173 assert(mlir::isa<cir::FPTypeInterface>(
type) &&
174 "expect floating-point type");
175 return builder.create<cir::ConstantOp>(
179 mlir::Value VisitCharacterLiteral(
const CharacterLiteral *e) {
180 mlir::Type ty = cgf.convertType(e->
getType());
181 auto init = cir::IntAttr::get(ty, e->
getValue());
182 return builder.create<cir::ConstantOp>(cgf.getLoc(e->
getExprLoc()), init);
185 mlir::Value VisitCXXBoolLiteralExpr(
const CXXBoolLiteralExpr *e) {
189 mlir::Value VisitCXXScalarValueInitExpr(
const CXXScalarValueInitExpr *e) {
196 mlir::Value VisitOpaqueValueExpr(OpaqueValueExpr *e) {
198 return emitLoadOfLValue(cgf.getOrCreateOpaqueLValueMapping(e),
202 return cgf.getOrCreateOpaqueRValueMapping(e).getValue();
205 mlir::Value VisitCastExpr(
CastExpr *e);
206 mlir::Value VisitCallExpr(
const CallExpr *e);
208 mlir::Value VisitStmtExpr(StmtExpr *e) {
209 CIRGenFunction::StmtExprEvaluation eval(cgf);
217 (void)cgf.emitCompoundStmt(*e->
getSubStmt(), &retAlloca);
219 return cgf.emitLoadOfScalar(cgf.makeAddrLValue(retAlloca, e->
getType()),
223 mlir::Value VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
228 const mlir::Value vecValue = Visit(e->
getBase());
229 const mlir::Value indexValue = Visit(e->
getIdx());
230 return cgf.builder.create<cir::VecExtractOp>(loc, vecValue, indexValue);
233 return emitLoadOfLValue(e);
236 mlir::Value VisitShuffleVectorExpr(ShuffleVectorExpr *e) {
239 mlir::Value inputVec = Visit(e->
getExpr(0));
240 mlir::Value indexVec = Visit(e->
getExpr(1));
241 return cgf.builder.create<cir::VecShuffleDynamicOp>(
245 mlir::Value vec1 = Visit(e->
getExpr(0));
246 mlir::Value vec2 = Visit(e->
getExpr(1));
251 SmallVector<mlir::Attribute, 8> indices;
254 cir::IntAttr::get(cgf.builder.getSInt64Ty(),
260 return cgf.builder.create<cir::VecShuffleOp>(
262 vec2, cgf.builder.getArrayAttr(indices));
265 mlir::Value VisitConvertVectorExpr(ConvertVectorExpr *e) {
268 return emitScalarConversion(Visit(e->
getSrcExpr()),
273 mlir::Value VisitMemberExpr(MemberExpr *e);
275 mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
276 return emitLoadOfLValue(e);
279 mlir::Value VisitInitListExpr(InitListExpr *e);
281 mlir::Value VisitExplicitCastExpr(ExplicitCastExpr *e) {
282 return VisitCastExpr(e);
285 mlir::Value VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *e) {
286 return cgf.cgm.emitNullConstant(e->
getType(),
291 mlir::Value emitPointerToBoolConversion(mlir::Value v, QualType qt) {
294 return cgf.getBuilder().createPtrToBoolCast(v);
297 mlir::Value emitFloatToBoolConversion(mlir::Value src, mlir::Location loc) {
298 cir::BoolType boolTy = builder.getBoolTy();
299 return builder.create<cir::CastOp>(loc, boolTy,
300 cir::CastKind::float_to_bool, src);
303 mlir::Value emitIntToBoolConversion(mlir::Value srcVal, mlir::Location loc) {
309 cir::BoolType boolTy = builder.getBoolTy();
310 return builder.create<cir::CastOp>(loc, boolTy, cir::CastKind::int_to_bool,
316 mlir::Value emitConversionToBool(mlir::Value src, QualType srcType,
317 mlir::Location loc) {
318 assert(srcType.
isCanonical() &&
"EmitScalarConversion strips typedefs");
321 return emitFloatToBoolConversion(src, loc);
323 if (llvm::isa<MemberPointerType>(srcType)) {
324 cgf.getCIRGenModule().errorNYI(loc,
"member pointer to bool conversion");
325 return builder.getFalse(loc);
329 return emitIntToBoolConversion(src, loc);
331 assert(::mlir::isa<cir::PointerType>(src.getType()));
332 return emitPointerToBoolConversion(src, srcType);
337 struct ScalarConversionOpts {
338 bool treatBooleanAsSigned;
339 bool emitImplicitIntegerTruncationChecks;
340 bool emitImplicitIntegerSignChangeChecks;
342 ScalarConversionOpts()
343 : treatBooleanAsSigned(
false),
344 emitImplicitIntegerTruncationChecks(
false),
345 emitImplicitIntegerSignChangeChecks(
false) {}
347 ScalarConversionOpts(clang::SanitizerSet sanOpts)
348 : treatBooleanAsSigned(
false),
349 emitImplicitIntegerTruncationChecks(
350 sanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)),
351 emitImplicitIntegerSignChangeChecks(
352 sanOpts.
has(SanitizerKind::ImplicitIntegerSignChange)) {}
359 mlir::Value emitScalarCast(mlir::Value src, QualType srcType,
360 QualType dstType, mlir::Type srcTy,
361 mlir::Type dstTy, ScalarConversionOpts opts) {
363 "Internal error: matrix types not handled by this function.");
364 assert(!(mlir::isa<mlir::IntegerType>(srcTy) ||
365 mlir::isa<mlir::IntegerType>(dstTy)) &&
366 "Obsolete code. Don't use mlir::IntegerType with CIR.");
368 mlir::Type fullDstTy = dstTy;
369 if (mlir::isa<cir::VectorType>(srcTy) &&
370 mlir::isa<cir::VectorType>(dstTy)) {
372 srcTy = mlir::dyn_cast<cir::VectorType>(srcTy).getElementType();
373 dstTy = mlir::dyn_cast<cir::VectorType>(dstTy).getElementType();
376 std::optional<cir::CastKind> castKind;
378 if (mlir::isa<cir::BoolType>(srcTy)) {
379 if (opts.treatBooleanAsSigned)
380 cgf.getCIRGenModule().errorNYI(
"signed bool");
381 if (cgf.getBuilder().isInt(dstTy))
382 castKind = cir::CastKind::bool_to_int;
383 else if (mlir::isa<cir::FPTypeInterface>(dstTy))
384 castKind = cir::CastKind::bool_to_float;
386 llvm_unreachable(
"Internal error: Cast to unexpected type");
387 }
else if (cgf.getBuilder().isInt(srcTy)) {
388 if (cgf.getBuilder().isInt(dstTy))
389 castKind = cir::CastKind::integral;
390 else if (mlir::isa<cir::FPTypeInterface>(dstTy))
391 castKind = cir::CastKind::int_to_float;
393 llvm_unreachable(
"Internal error: Cast to unexpected type");
394 }
else if (mlir::isa<cir::FPTypeInterface>(srcTy)) {
395 if (cgf.getBuilder().isInt(dstTy)) {
399 if (!cgf.cgm.getCodeGenOpts().StrictFloatCastOverflow)
400 cgf.getCIRGenModule().errorNYI(
"strict float cast overflow");
402 castKind = cir::CastKind::float_to_int;
403 }
else if (mlir::isa<cir::FPTypeInterface>(dstTy)) {
405 return builder.createFloatingCast(src, fullDstTy);
407 llvm_unreachable(
"Internal error: Cast to unexpected type");
410 llvm_unreachable(
"Internal error: Cast from unexpected type");
413 assert(castKind.has_value() &&
"Internal error: CastKind not set.");
414 return builder.create<cir::CastOp>(src.getLoc(), fullDstTy, *castKind, src);
418 VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e) {
422 mlir::Value VisitVAArgExpr(VAArgExpr *ve) {
427 "variably modified types in varargs");
430 return cgf.emitVAArg(ve);
433 mlir::Value VisitUnaryExprOrTypeTraitExpr(
const UnaryExprOrTypeTraitExpr *e);
435 VisitAbstractConditionalOperator(
const AbstractConditionalOperator *e);
438 mlir::Value VisitUnaryPostDec(
const UnaryOperator *e) {
440 return emitScalarPrePostIncDec(e, lv, cir::UnaryOpKind::Dec,
false);
442 mlir::Value VisitUnaryPostInc(
const UnaryOperator *e) {
444 return emitScalarPrePostIncDec(e, lv, cir::UnaryOpKind::Inc,
false);
446 mlir::Value VisitUnaryPreDec(
const UnaryOperator *e) {
448 return emitScalarPrePostIncDec(e, lv, cir::UnaryOpKind::Dec,
true);
450 mlir::Value VisitUnaryPreInc(
const UnaryOperator *e) {
452 return emitScalarPrePostIncDec(e, lv, cir::UnaryOpKind::Inc,
true);
454 mlir::Value emitScalarPrePostIncDec(
const UnaryOperator *e, LValue lv,
455 cir::UnaryOpKind kind,
bool isPre) {
456 if (cgf.getLangOpts().OpenMP)
464 if (
type->getAs<AtomicType>()) {
468 value = cgf.emitLoadOfLValue(lv, e->
getExprLoc()).getValue();
471 value = cgf.emitLoadOfLValue(lv, e->
getExprLoc()).getValue();
484 if (kind == cir::UnaryOpKind::Inc &&
type->isBooleanType()) {
485 value = builder.getTrue(cgf.getLoc(e->
getExprLoc()));
486 }
else if (
type->isIntegerType()) {
487 QualType promotedType;
488 [[maybe_unused]]
bool canPerformLossyDemotionCheck =
false;
489 if (cgf.getContext().isPromotableIntegerType(
type)) {
490 promotedType = cgf.getContext().getPromotedIntegerType(
type);
491 assert(promotedType !=
type &&
"Shouldn't promote to the same type.");
492 canPerformLossyDemotionCheck =
true;
493 canPerformLossyDemotionCheck &=
494 cgf.getContext().getCanonicalType(
type) !=
495 cgf.getContext().getCanonicalType(promotedType);
496 canPerformLossyDemotionCheck &=
503 (!canPerformLossyDemotionCheck ||
504 type->isSignedIntegerOrEnumerationType() ||
506 mlir::cast<cir::IntType>(cgf.convertType(
type)).getWidth() ==
507 mlir::cast<cir::IntType>(cgf.convertType(
type)).getWidth()) &&
508 "The following check expects that if we do promotion to different "
509 "underlying canonical type, at least one of the types (either "
510 "base or promoted) will be signed, or the bitwidths will match.");
515 value = emitIncDecConsiderOverflowBehavior(e, value, kind);
517 cir::UnaryOpKind
kind =
518 e->
isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;
520 value = emitUnaryOp(e, kind, input,
false);
522 }
else if (
const PointerType *ptr =
type->getAs<PointerType>()) {
523 QualType
type = ptr->getPointeeType();
524 if (cgf.getContext().getAsVariableArrayType(
type)) {
526 cgf.cgm.errorNYI(e->
getSourceRange(),
"Pointer arithmetic on VLA");
528 }
else if (
type->isFunctionType()) {
531 "Pointer arithmetic on function pointer");
536 CIRGenBuilderTy &builder = cgf.getBuilder();
537 int amount =
kind == cir::UnaryOpKind::Inc ? 1 : -1;
538 mlir::Value amt = builder.getSInt32(amount, loc);
540 value = builder.createPtrStride(loc, value, amt);
542 }
else if (
type->isVectorType()) {
545 }
else if (
type->isRealFloatingType()) {
548 if (
type->isHalfType() &&
549 !cgf.getContext().getLangOpts().NativeHalfType) {
554 if (mlir::isa<cir::SingleType, cir::DoubleType>(value.getType())) {
557 assert(kind == cir::UnaryOpKind::Inc ||
558 kind == cir::UnaryOpKind::Dec &&
"Invalid UnaryOp kind");
559 value = emitUnaryOp(e, kind, value);
561 cgf.cgm.errorNYI(e->
getSourceRange(),
"Unary inc/dec other fp type");
564 }
else if (
type->isFixedPointType()) {
565 cgf.cgm.errorNYI(e->
getSourceRange(),
"Unary inc/dec other fixed point");
568 assert(
type->castAs<ObjCObjectPointerType>());
569 cgf.cgm.errorNYI(e->
getSourceRange(),
"Unary inc/dec ObjectiveC pointer");
573 CIRGenFunction::SourceLocRAIIObject sourceloc{
578 return cgf.emitStoreThroughBitfieldLValue(
RValue::get(value), lv);
580 cgf.emitStoreThroughLValue(
RValue::get(value), lv);
584 return isPre ? value : input;
587 mlir::Value emitIncDecConsiderOverflowBehavior(
const UnaryOperator *e,
589 cir::UnaryOpKind kind) {
590 assert(kind == cir::UnaryOpKind::Inc ||
591 kind == cir::UnaryOpKind::Dec &&
"Invalid UnaryOp kind");
592 switch (cgf.getLangOpts().getSignedOverflowBehavior()) {
593 case LangOptions::SOB_Defined:
594 return emitUnaryOp(e, kind, inVal,
false);
595 case LangOptions::SOB_Undefined:
597 return emitUnaryOp(e, kind, inVal,
true);
598 case LangOptions::SOB_Trapping:
600 return emitUnaryOp(e, kind, inVal,
true);
601 cgf.cgm.errorNYI(e->
getSourceRange(),
"inc/def overflow SOB_Trapping");
604 llvm_unreachable(
"Unexpected signed overflow behavior kind");
607 mlir::Value VisitUnaryAddrOf(
const UnaryOperator *e) {
608 if (llvm::isa<MemberPointerType>(e->
getType())) {
609 cgf.cgm.errorNYI(e->
getSourceRange(),
"Address of member pointer");
610 return builder.getNullPtr(cgf.convertType(e->
getType()),
614 return cgf.emitLValue(e->
getSubExpr()).getPointer();
617 mlir::Value VisitUnaryDeref(
const UnaryOperator *e) {
620 return emitLoadOfLValue(e);
623 mlir::Value VisitUnaryPlus(
const UnaryOperator *e) {
626 emitUnaryPlusOrMinus(e, cir::UnaryOpKind::Plus, promotionType);
627 if (result && !promotionType.
isNull())
628 return emitUnPromotedValue(result, e->
getType());
632 mlir::Value VisitUnaryMinus(
const UnaryOperator *e) {
635 emitUnaryPlusOrMinus(e, cir::UnaryOpKind::Minus, promotionType);
636 if (result && !promotionType.
isNull())
637 return emitUnPromotedValue(result, e->
getType());
641 mlir::Value emitUnaryPlusOrMinus(
const UnaryOperator *e,
642 cir::UnaryOpKind kind,
643 QualType promotionType) {
644 ignoreResultAssign =
false;
646 if (!promotionType.
isNull())
647 operand = cgf.emitPromotedScalarExpr(e->
getSubExpr(), promotionType);
656 return emitUnaryOp(e, kind, operand, nsw);
659 mlir::Value emitUnaryOp(
const UnaryOperator *e, cir::UnaryOpKind kind,
660 mlir::Value input,
bool nsw =
false) {
661 return builder.create<cir::UnaryOp>(
666 mlir::Value VisitUnaryNot(
const UnaryOperator *e) {
667 ignoreResultAssign =
false;
669 return emitUnaryOp(e, cir::UnaryOpKind::Not, op);
672 mlir::Value VisitUnaryLNot(
const UnaryOperator *e);
674 mlir::Value VisitUnaryReal(
const UnaryOperator *e);
675 mlir::Value VisitUnaryImag(
const UnaryOperator *e);
676 mlir::Value VisitRealImag(
const UnaryOperator *e,
677 QualType promotionType = QualType());
679 mlir::Value VisitUnaryExtension(
const UnaryOperator *e) {
683 mlir::Value VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
684 CIRGenFunction::CXXDefaultInitExprScope scope(cgf, die);
688 mlir::Value VisitCXXThisExpr(CXXThisExpr *te) {
return cgf.loadCXXThis(); }
690 mlir::Value VisitExprWithCleanups(ExprWithCleanups *e);
691 mlir::Value VisitCXXNewExpr(
const CXXNewExpr *e) {
692 return cgf.emitCXXNewExpr(e);
694 mlir::Value VisitCXXDeleteExpr(
const CXXDeleteExpr *e) {
695 cgf.emitCXXDeleteExpr(e);
699 mlir::Value VisitCXXThrowExpr(
const CXXThrowExpr *e) {
700 cgf.emitCXXThrowExpr(e);
709 emitScalarConversion(mlir::Value src, QualType srcType, QualType dstType,
711 ScalarConversionOpts opts = ScalarConversionOpts()) {
721 cgf.getCIRGenModule().errorNYI(loc,
"fixed point conversions");
727 if (srcType == dstType) {
728 if (opts.emitImplicitIntegerSignChangeChecks)
729 cgf.getCIRGenModule().errorNYI(loc,
730 "implicit integer sign change checks");
737 mlir::Type mlirSrcType = src.getType();
742 return emitConversionToBool(src, srcType, cgf.getLoc(loc));
744 mlir::Type mlirDstType = cgf.convertType(dstType);
747 !cgf.getContext().getLangOpts().NativeHalfType) {
749 if (mlir::isa<cir::FPTypeInterface>(mlirDstType)) {
750 if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics())
751 cgf.getCIRGenModule().errorNYI(loc,
752 "cast via llvm.convert.from.fp16");
757 if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics())
758 cgf.getCIRGenModule().errorNYI(loc,
759 "cast via llvm.convert.from.fp16");
762 src = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, src,
764 srcType = cgf.getContext().FloatTy;
765 mlirSrcType = cgf.FloatTy;
771 if (mlirSrcType == mlirDstType) {
772 if (opts.emitImplicitIntegerSignChangeChecks)
773 cgf.getCIRGenModule().errorNYI(loc,
774 "implicit integer sign change checks");
781 if (
auto dstPT = dyn_cast<cir::PointerType>(mlirDstType)) {
782 cgf.getCIRGenModule().errorNYI(loc,
"pointer casts");
783 return builder.getNullPtr(dstPT, src.getLoc());
789 return builder.createPtrToInt(src, mlirDstType);
796 assert(dstType->
castAs<ExtVectorType>()->getElementType().getTypePtr() ==
798 "Splatted expr doesn't match with vector element type?");
800 cgf.getCIRGenModule().errorNYI(loc,
"vector splatting");
805 cgf.getCIRGenModule().errorNYI(loc,
806 "matrix type to matrix type conversion");
810 "Internal error: conversion between matrix type and scalar type");
813 mlir::Value res =
nullptr;
814 mlir::Type resTy = mlirDstType;
816 res = emitScalarCast(src, srcType, dstType, mlirSrcType, mlirDstType, opts);
818 if (mlirDstType != resTy) {
819 if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
820 cgf.getCIRGenModule().errorNYI(loc,
"cast via llvm.convert.to.fp16");
824 res = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, res,
828 if (opts.emitImplicitIntegerTruncationChecks)
829 cgf.getCIRGenModule().errorNYI(loc,
"implicit integer truncation checks");
831 if (opts.emitImplicitIntegerSignChangeChecks)
832 cgf.getCIRGenModule().errorNYI(loc,
833 "implicit integer sign change checks");
838 BinOpInfo emitBinOps(
const BinaryOperator *e,
839 QualType promotionType = QualType()) {
841 result.lhs = cgf.emitPromotedScalarExpr(e->
getLHS(), promotionType);
842 result.rhs = cgf.emitPromotedScalarExpr(e->
getRHS(), promotionType);
843 if (!promotionType.
isNull())
844 result.fullType = promotionType;
846 result.fullType = e->
getType();
847 result.compType = result.fullType;
848 if (
const auto *vecType = dyn_cast_or_null<VectorType>(result.fullType)) {
849 result.compType = vecType->getElementType();
859 mlir::Value emitMul(
const BinOpInfo &ops);
860 mlir::Value emitDiv(
const BinOpInfo &ops);
861 mlir::Value emitRem(
const BinOpInfo &ops);
862 mlir::Value emitAdd(
const BinOpInfo &ops);
863 mlir::Value emitSub(
const BinOpInfo &ops);
864 mlir::Value emitShl(
const BinOpInfo &ops);
865 mlir::Value emitShr(
const BinOpInfo &ops);
866 mlir::Value emitAnd(
const BinOpInfo &ops);
867 mlir::Value emitXor(
const BinOpInfo &ops);
868 mlir::Value emitOr(
const BinOpInfo &ops);
870 LValue emitCompoundAssignLValue(
871 const CompoundAssignOperator *e,
872 mlir::Value (ScalarExprEmitter::*f)(
const BinOpInfo &),
873 mlir::Value &result);
875 emitCompoundAssign(
const CompoundAssignOperator *e,
876 mlir::Value (ScalarExprEmitter::*f)(
const BinOpInfo &));
880 QualType getPromotionType(QualType ty) {
881 const clang::ASTContext &ctx = cgf.getContext();
882 if (
auto *complexTy = ty->
getAs<ComplexType>()) {
883 QualType elementTy = complexTy->getElementType();
889 if (
auto *vt = ty->
getAs<VectorType>()) {
890 unsigned numElements = vt->getNumElements();
893 return cgf.getContext().FloatTy;
900#define HANDLEBINOP(OP) \
901 mlir::Value VisitBin##OP(const BinaryOperator *e) { \
902 QualType promotionTy = getPromotionType(e->getType()); \
903 auto result = emit##OP(emitBinOps(e, promotionTy)); \
904 if (result && !promotionTy.isNull()) \
905 result = emitUnPromotedValue(result, e->getType()); \
908 mlir::Value VisitBin##OP##Assign(const CompoundAssignOperator *e) { \
909 return emitCompoundAssign(e, &ScalarExprEmitter::emit##OP); \
930 auto clangCmpToCIRCmp =
934 return cir::CmpOpKind::lt;
936 return cir::CmpOpKind::gt;
938 return cir::CmpOpKind::le;
940 return cir::CmpOpKind::ge;
942 return cir::CmpOpKind::eq;
944 return cir::CmpOpKind::ne;
946 llvm_unreachable(
"unsupported comparison kind for cir.cmp");
950 cir::CmpOpKind kind = clangCmpToCIRCmp(e->
getOpcode());
958 BinOpInfo boInfo = emitBinOps(e);
959 mlir::Value lhs = boInfo.lhs;
960 mlir::Value rhs = boInfo.rhs;
970 result = builder.create<cir::VecCmpOp>(
972 boInfo.lhs, boInfo.rhs);
974 }
else if (boInfo.isFixedPointOp()) {
977 result = builder.
getBool(
false, loc);
981 mlir::isa<cir::PointerType>(lhs.getType()) &&
982 mlir::isa<cir::PointerType>(rhs.getType())) {
983 cgf.
cgm.
errorNYI(loc,
"strict vtable pointer comparisons");
986 cir::CmpOpKind kind = clangCmpToCIRCmp(e->
getOpcode());
993 BinOpInfo boInfo = emitBinOps(e);
994 result = builder.create<cir::CmpOp>(loc, kind, boInfo.lhs, boInfo.rhs);
1002#define VISITCOMP(CODE) \
1003 mlir::Value VisitBin##CODE(const BinaryOperator *E) { return emitCmp(E); }
1013 const bool ignore = std::exchange(ignoreResultAssign,
false);
1028 rhs = Visit(e->
getRHS());
1038 if (lhs.isBitField()) {
1058 if (!lhs.isVolatile())
1062 return emitLoadOfLValue(lhs, e->
getExprLoc());
1065 mlir::Value VisitBinComma(
const BinaryOperator *e) {
1066 cgf.emitIgnoredExpr(e->
getLHS());
1068 return Visit(e->
getRHS());
1071 mlir::Value VisitBinLAnd(
const clang::BinaryOperator *e) {
1073 mlir::Location loc = cgf.getLoc(e->
getExprLoc());
1074 auto vecTy = mlir::cast<cir::VectorType>(cgf.convertType(e->
getType()));
1075 mlir::Value zeroValue = builder.getNullValue(vecTy.getElementType(), loc);
1076 SmallVector<mlir::Value, 16> elements(vecTy.getSize(), zeroValue);
1077 auto zeroVec = cir::VecCreateOp::create(builder, loc, vecTy, elements);
1079 mlir::Value lhs = Visit(e->
getLHS());
1080 mlir::Value rhs = Visit(e->
getRHS());
1082 auto cmpOpKind = cir::CmpOpKind::ne;
1083 lhs = cir::VecCmpOp::create(builder, loc, vecTy, cmpOpKind, lhs, zeroVec);
1084 rhs = cir::VecCmpOp::create(builder, loc, vecTy, cmpOpKind, rhs, zeroVec);
1085 mlir::Value vecOr = builder.createAnd(loc, lhs, rhs);
1086 return builder.createIntCast(vecOr, vecTy);
1090 mlir::Type resTy = cgf.convertType(e->
getType());
1091 mlir::Location loc = cgf.getLoc(e->
getExprLoc());
1093 CIRGenFunction::ConditionalEvaluation eval(cgf);
1095 mlir::Value lhsCondV = cgf.evaluateExprAsBool(e->
getLHS());
1096 auto resOp = builder.create<cir::TernaryOp>(
1098 [&](mlir::OpBuilder &
b, mlir::Location loc) {
1099 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1100 b.getInsertionBlock()};
1101 cgf.curLexScope->setAsTernary();
1102 mlir::Value res = cgf.evaluateExprAsBool(e->
getRHS());
1104 cir::YieldOp::create(
b, loc, res);
1107 [&](mlir::OpBuilder &
b, mlir::Location loc) {
1108 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1109 b.getInsertionBlock()};
1111 auto res = cir::ConstantOp::create(
b, loc, builder.getFalseAttr());
1112 cir::YieldOp::create(
b, loc, res.getRes());
1114 return maybePromoteBoolResult(resOp.getResult(), resTy);
1117 mlir::Value VisitBinLOr(
const clang::BinaryOperator *e) {
1119 mlir::Location loc = cgf.getLoc(e->
getExprLoc());
1120 auto vecTy = mlir::cast<cir::VectorType>(cgf.convertType(e->
getType()));
1121 mlir::Value zeroValue = builder.getNullValue(vecTy.getElementType(), loc);
1122 SmallVector<mlir::Value, 16> elements(vecTy.getSize(), zeroValue);
1123 auto zeroVec = cir::VecCreateOp::create(builder, loc, vecTy, elements);
1125 mlir::Value lhs = Visit(e->
getLHS());
1126 mlir::Value rhs = Visit(e->
getRHS());
1128 auto cmpOpKind = cir::CmpOpKind::ne;
1129 lhs = cir::VecCmpOp::create(builder, loc, vecTy, cmpOpKind, lhs, zeroVec);
1130 rhs = cir::VecCmpOp::create(builder, loc, vecTy, cmpOpKind, rhs, zeroVec);
1131 mlir::Value vecOr = builder.createOr(loc, lhs, rhs);
1132 return builder.createIntCast(vecOr, vecTy);
1136 mlir::Type resTy = cgf.convertType(e->
getType());
1137 mlir::Location loc = cgf.getLoc(e->
getExprLoc());
1139 CIRGenFunction::ConditionalEvaluation eval(cgf);
1141 mlir::Value lhsCondV = cgf.evaluateExprAsBool(e->
getLHS());
1142 auto resOp = builder.create<cir::TernaryOp>(
1144 [&](mlir::OpBuilder &
b, mlir::Location loc) {
1145 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1146 b.getInsertionBlock()};
1148 auto res = cir::ConstantOp::create(
b, loc, builder.getTrueAttr());
1149 cir::YieldOp::create(
b, loc, res.getRes());
1152 [&](mlir::OpBuilder &
b, mlir::Location loc) {
1153 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1154 b.getInsertionBlock()};
1156 mlir::Value res = cgf.evaluateExprAsBool(e->
getRHS());
1158 cir::YieldOp::create(
b, loc, res);
1161 return maybePromoteBoolResult(resOp.getResult(), resTy);
1164 mlir::Value VisitAtomicExpr(AtomicExpr *e) {
1165 return cgf.emitAtomicExpr(e).getValue();
1169LValue ScalarExprEmitter::emitCompoundAssignLValue(
1171 mlir::Value (ScalarExprEmitter::*func)(
const BinOpInfo &),
1172 mlir::Value &result) {
1183 if (promotionTypeCR.
isNull())
1187 QualType promotionTypeRHS = getPromotionType(e->
getRHS()->
getType());
1189 if (!promotionTypeRHS.
isNull())
1192 opInfo.rhs = Visit(e->
getRHS());
1194 opInfo.fullType = promotionTypeCR;
1195 opInfo.compType = opInfo.fullType;
1196 if (
const auto *vecType = dyn_cast_or_null<VectorType>(opInfo.fullType))
1197 opInfo.compType = vecType->getElementType();
1206 if (lhsTy->
getAs<AtomicType>()) {
1207 cgf.
cgm.
errorNYI(result.getLoc(),
"atomic lvalue assign");
1211 opInfo.lhs = emitLoadOfLValue(lhsLV, e->
getExprLoc());
1213 CIRGenFunction::SourceLocRAIIObject sourceloc{
1216 if (!promotionTypeLHS.
isNull())
1217 opInfo.lhs = emitScalarConversion(opInfo.lhs, lhsTy, promotionTypeLHS, loc);
1219 opInfo.lhs = emitScalarConversion(opInfo.lhs, lhsTy,
1223 result = (this->*func)(opInfo);
1227 result = emitScalarConversion(result, promotionTypeCR, lhsTy, loc,
1228 ScalarConversionOpts(cgf.
sanOpts));
1234 if (lhsLV.isBitField())
1245mlir::Value ScalarExprEmitter::emitComplexToScalarConversion(mlir::Location lov,
1249 cir::CastKind castOpKind;
1251 case CK_FloatingComplexToReal:
1252 castOpKind = cir::CastKind::float_complex_to_real;
1254 case CK_IntegralComplexToReal:
1255 castOpKind = cir::CastKind::int_complex_to_real;
1257 case CK_FloatingComplexToBoolean:
1258 castOpKind = cir::CastKind::float_complex_to_bool;
1260 case CK_IntegralComplexToBoolean:
1261 castOpKind = cir::CastKind::int_complex_to_bool;
1264 llvm_unreachable(
"invalid complex-to-scalar cast kind");
1270mlir::Value ScalarExprEmitter::emitPromoted(
const Expr *e,
1271 QualType promotionType) {
1273 if (
const auto *bo = dyn_cast<BinaryOperator>(e)) {
1274 switch (bo->getOpcode()) {
1275#define HANDLE_BINOP(OP) \
1277 return emit##OP(emitBinOps(bo, promotionType));
1286 }
else if (
const auto *uo = dyn_cast<UnaryOperator>(e)) {
1287 switch (uo->getOpcode()) {
1290 return VisitRealImag(uo, promotionType);
1292 return emitUnaryPlusOrMinus(uo, cir::UnaryOpKind::Minus, promotionType);
1294 return emitUnaryPlusOrMinus(uo, cir::UnaryOpKind::Plus, promotionType);
1299 mlir::Value result = Visit(
const_cast<Expr *
>(e));
1301 if (!promotionType.
isNull())
1302 return emitPromotedValue(result, promotionType);
1303 return emitUnPromotedValue(result, e->
getType());
1308mlir::Value ScalarExprEmitter::emitCompoundAssign(
1309 const CompoundAssignOperator *e,
1310 mlir::Value (ScalarExprEmitter::*func)(
const BinOpInfo &)) {
1312 bool ignore = std::exchange(ignoreResultAssign,
false);
1314 LValue lhs = emitCompoundAssignLValue(e, func, rhs);
1325 if (!lhs.isVolatile())
1329 return emitLoadOfLValue(lhs, e->
getExprLoc());
1332mlir::Value ScalarExprEmitter::VisitExprWithCleanups(ExprWithCleanups *e) {
1334 mlir::OpBuilder &builder = cgf.builder;
1336 auto scope = cir::ScopeOp::create(
1339 [&](mlir::OpBuilder &
b, mlir::Type &yieldTy, mlir::Location loc) {
1340 CIRGenFunction::LexicalScope lexScope{cgf, loc,
1341 builder.getInsertionBlock()};
1342 mlir::Value scopeYieldVal = Visit(e->
getSubExpr());
1343 if (scopeYieldVal) {
1347 cir::YieldOp::create(builder, loc, scopeYieldVal);
1348 yieldTy = scopeYieldVal.getType();
1352 return scope.getNumResults() > 0 ? scope->getResult(0) :
nullptr;
1362#define COMPOUND_OP(Op) \
1363 case BO_##Op##Assign: \
1364 return emitter.emitCompoundAssignLValue(e, &ScalarExprEmitter::emit##Op, \
1401 llvm_unreachable(
"Not valid compound assignment operators");
1403 llvm_unreachable(
"Unhandled compound assignment operator");
1409 "Invalid scalar expression to emit");
1416 if (!promotionType.
isNull())
1431static std::optional<QualType>
1435 return std::nullopt;
1440 return std::nullopt;
1453 const BinOpInfo &op) {
1455 "Expected a unary or binary operator");
1459 if (!op.mayHaveIntegerOverflow())
1463 if (
const auto *uo = dyn_cast<UnaryOperator>(op.e))
1464 return !uo->canOverflow();
1469 std::optional<QualType> optionalLHSTy =
1474 std::optional<QualType> optionalRHSTy =
1484 if ((op.opcode != BO_Mul && op.opcode != BO_MulAssign) ||
1491 return (2 * astContext.
getTypeSize(lhsTy)) < promotedSize ||
1492 (2 * astContext.
getTypeSize(rhsTy)) < promotedSize;
1497 const BinOpInfo &op,
1498 bool isSubtraction) {
1503 mlir::Value pointer = op.lhs;
1504 Expr *pointerOperand =
expr->getLHS();
1505 mlir::Value
index = op.rhs;
1506 Expr *indexOperand =
expr->getRHS();
1512 if (!isSubtraction && !mlir::isa<cir::PointerType>(pointer.getType())) {
1513 std::swap(pointer,
index);
1514 std::swap(pointerOperand, indexOperand);
1516 assert(mlir::isa<cir::PointerType>(pointer.getType()) &&
1517 "Need a pointer operand");
1518 assert(mlir::isa<cir::IntType>(
index.getType()) &&
"Need an integer operand");
1553 cgf.
cgm.
errorNYI(
"Objective-C:pointer arithmetic with non-pointer type");
1564 cgf.
cgm.
errorNYI(
"void* or function pointer arithmetic");
1569 return cgf.
getBuilder().create<cir::PtrStrideOp>(
1573mlir::Value ScalarExprEmitter::emitMul(
const BinOpInfo &ops) {
1574 const mlir::Location loc = cgf.
getLoc(ops.loc);
1576 switch (cgf.
getLangOpts().getSignedOverflowBehavior()) {
1577 case LangOptions::SOB_Defined:
1578 if (!cgf.
sanOpts.
has(SanitizerKind::SignedIntegerOverflow))
1579 return builder.createMul(loc, ops.lhs, ops.rhs);
1581 case LangOptions::SOB_Undefined:
1582 if (!cgf.
sanOpts.
has(SanitizerKind::SignedIntegerOverflow))
1583 return builder.createNSWMul(loc, ops.lhs, ops.rhs);
1585 case LangOptions::SOB_Trapping:
1587 return builder.createNSWMul(loc, ops.lhs, ops.rhs);
1597 cgf.
sanOpts.
has(SanitizerKind::UnsignedIntegerOverflow) &&
1599 cgf.
cgm.
errorNYI(
"unsigned int overflow sanitizer");
1601 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
1603 return builder.createFMul(loc, ops.lhs, ops.rhs);
1606 if (ops.isFixedPointOp()) {
1612 return builder.create<cir::BinOp>(cgf.
getLoc(ops.loc),
1614 cir::BinOpKind::Mul, ops.lhs, ops.rhs);
1616mlir::Value ScalarExprEmitter::emitDiv(
const BinOpInfo &ops) {
1617 return builder.create<cir::BinOp>(cgf.
getLoc(ops.loc),
1619 cir::BinOpKind::Div, ops.lhs, ops.rhs);
1621mlir::Value ScalarExprEmitter::emitRem(
const BinOpInfo &ops) {
1622 return builder.create<cir::BinOp>(cgf.
getLoc(ops.loc),
1624 cir::BinOpKind::Rem, ops.lhs, ops.rhs);
1627mlir::Value ScalarExprEmitter::emitAdd(
const BinOpInfo &ops) {
1628 if (mlir::isa<cir::PointerType>(ops.lhs.getType()) ||
1629 mlir::isa<cir::PointerType>(ops.rhs.getType()))
1632 const mlir::Location loc = cgf.
getLoc(ops.loc);
1634 switch (cgf.
getLangOpts().getSignedOverflowBehavior()) {
1635 case LangOptions::SOB_Defined:
1636 if (!cgf.
sanOpts.
has(SanitizerKind::SignedIntegerOverflow))
1637 return builder.createAdd(loc, ops.lhs, ops.rhs);
1639 case LangOptions::SOB_Undefined:
1640 if (!cgf.
sanOpts.
has(SanitizerKind::SignedIntegerOverflow))
1641 return builder.createNSWAdd(loc, ops.lhs, ops.rhs);
1643 case LangOptions::SOB_Trapping:
1645 return builder.createNSWAdd(loc, ops.lhs, ops.rhs);
1656 cgf.
sanOpts.
has(SanitizerKind::UnsignedIntegerOverflow) &&
1658 cgf.
cgm.
errorNYI(
"unsigned int overflow sanitizer");
1660 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
1662 return builder.createFAdd(loc, ops.lhs, ops.rhs);
1665 if (ops.isFixedPointOp()) {
1671 return builder.create<cir::BinOp>(loc, cgf.
convertType(ops.fullType),
1672 cir::BinOpKind::Add, ops.lhs, ops.rhs);
1675mlir::Value ScalarExprEmitter::emitSub(
const BinOpInfo &ops) {
1676 const mlir::Location loc = cgf.
getLoc(ops.loc);
1678 if (!mlir::isa<cir::PointerType>(ops.lhs.getType())) {
1680 switch (cgf.
getLangOpts().getSignedOverflowBehavior()) {
1681 case LangOptions::SOB_Defined: {
1682 if (!cgf.
sanOpts.
has(SanitizerKind::SignedIntegerOverflow))
1683 return builder.createSub(loc, ops.lhs, ops.rhs);
1686 case LangOptions::SOB_Undefined:
1687 if (!cgf.
sanOpts.
has(SanitizerKind::SignedIntegerOverflow))
1688 return builder.createNSWSub(loc, ops.lhs, ops.rhs);
1690 case LangOptions::SOB_Trapping:
1692 return builder.createNSWSub(loc, ops.lhs, ops.rhs);
1704 cgf.
sanOpts.
has(SanitizerKind::UnsignedIntegerOverflow) &&
1706 cgf.
cgm.
errorNYI(
"unsigned int overflow sanitizer");
1708 if (cir::isFPOrVectorOfFPType(ops.lhs.getType())) {
1710 return builder.createFSub(loc, ops.lhs, ops.rhs);
1713 if (ops.isFixedPointOp()) {
1719 return builder.create<cir::BinOp>(cgf.
getLoc(ops.loc),
1721 cir::BinOpKind::Sub, ops.lhs, ops.rhs);
1726 if (!mlir::isa<cir::PointerType>(ops.rhs.getType()))
1742mlir::Value ScalarExprEmitter::emitShl(
const BinOpInfo &ops) {
1744 if (ops.isFixedPointOp()) {
1754 bool sanitizeSignedBase = cgf.
sanOpts.
has(SanitizerKind::ShiftBase) &&
1758 bool sanitizeUnsignedBase =
1759 cgf.
sanOpts.
has(SanitizerKind::UnsignedShiftBase) &&
1761 bool sanitizeBase = sanitizeSignedBase || sanitizeUnsignedBase;
1762 bool sanitizeExponent = cgf.
sanOpts.
has(SanitizerKind::ShiftExponent);
1767 else if ((sanitizeBase || sanitizeExponent) &&
1768 mlir::isa<cir::IntType>(ops.lhs.getType()))
1771 return builder.createShiftLeft(cgf.
getLoc(ops.loc), ops.lhs, ops.rhs);
1774mlir::Value ScalarExprEmitter::emitShr(
const BinOpInfo &ops) {
1776 if (ops.isFixedPointOp()) {
1789 else if (cgf.
sanOpts.
has(SanitizerKind::ShiftExponent) &&
1790 mlir::isa<cir::IntType>(ops.lhs.getType()))
1795 return builder.createShiftRight(cgf.
getLoc(ops.loc), ops.lhs, ops.rhs);
1798mlir::Value ScalarExprEmitter::emitAnd(
const BinOpInfo &ops) {
1799 return builder.create<cir::BinOp>(cgf.
getLoc(ops.loc),
1801 cir::BinOpKind::And, ops.lhs, ops.rhs);
1803mlir::Value ScalarExprEmitter::emitXor(
const BinOpInfo &ops) {
1804 return builder.create<cir::BinOp>(cgf.
getLoc(ops.loc),
1806 cir::BinOpKind::Xor, ops.lhs, ops.rhs);
1808mlir::Value ScalarExprEmitter::emitOr(
const BinOpInfo &ops) {
1809 return builder.create<cir::BinOp>(cgf.
getLoc(ops.loc),
1811 cir::BinOpKind::Or, ops.lhs, ops.rhs);
1818mlir::Value ScalarExprEmitter::VisitCastExpr(
CastExpr *ce) {
1820 QualType destTy = ce->
getType();
1825 ignoreResultAssign =
false;
1828 case clang::CK_Dependent:
1829 llvm_unreachable(
"dependent cast kind in CIR gen!");
1830 case clang::CK_BuiltinFnToFnPtr:
1831 llvm_unreachable(
"builtin functions are handled elsewhere");
1833 case CK_CPointerToObjCPointerCast:
1834 case CK_BlockPointerToObjCPointerCast:
1835 case CK_AnyPointerToBlockPointerCast:
1837 mlir::Value src = Visit(
const_cast<Expr *
>(subExpr));
1842 if (cgf.
sanOpts.
has(SanitizerKind::CFIUnrelatedCast))
1844 "sanitizer support");
1848 "strict vtable pointers");
1875 case CK_AtomicToNonAtomic: {
1881 case CK_NonAtomicToAtomic:
1882 case CK_UserDefinedConversion:
1883 return Visit(
const_cast<Expr *
>(subExpr));
1885 auto v = Visit(
const_cast<Expr *
>(subExpr));
1891 if (t != v.getType())
1896 case CK_IntegralToPointer: {
1898 mlir::Value src = Visit(
const_cast<Expr *
>(subExpr));
1905 mlir::Value middleVal = builder.createCast(
1907 : cir::CastKind::integral,
1912 "IntegralToPointer: strict vtable pointers");
1916 return builder.createIntToPtr(middleVal, destCIRTy);
1924 case CK_ArrayToPointerDecay:
1927 case CK_NullToPointer: {
1937 case CK_LValueToRValue:
1939 assert(subExpr->
isGLValue() &&
"lvalue-to-rvalue applied to r-value!");
1940 return Visit(
const_cast<Expr *
>(subExpr));
1942 case CK_IntegralCast: {
1943 ScalarConversionOpts opts;
1944 if (
auto *ice = dyn_cast<ImplicitCastExpr>(ce)) {
1945 if (!ice->isPartOfExplicitCast())
1946 opts = ScalarConversionOpts(cgf.
sanOpts);
1948 return emitScalarConversion(Visit(subExpr), subExpr->
getType(), destTy,
1952 case CK_FloatingComplexToReal:
1953 case CK_IntegralComplexToReal:
1954 case CK_FloatingComplexToBoolean:
1955 case CK_IntegralComplexToBoolean: {
1961 case CK_FloatingRealToComplex:
1962 case CK_FloatingComplexCast:
1963 case CK_IntegralRealToComplex:
1964 case CK_IntegralComplexCast:
1965 case CK_IntegralComplexToFloatingComplex:
1966 case CK_FloatingComplexToIntegralComplex:
1967 llvm_unreachable(
"scalar cast to non-scalar value");
1969 case CK_PointerToIntegral: {
1970 assert(!destTy->
isBooleanType() &&
"bool should use PointerToBool");
1973 "strict vtable pointers");
1974 return builder.createPtrToInt(Visit(subExpr), cgf.
convertType(destTy));
1980 case CK_IntegralToFloating:
1981 case CK_FloatingToIntegral:
1982 case CK_FloatingCast:
1983 case CK_FixedPointToFloating:
1984 case CK_FloatingToFixedPoint: {
1985 if (kind == CK_FixedPointToFloating || kind == CK_FloatingToFixedPoint) {
1987 "fixed point casts");
1991 return emitScalarConversion(Visit(subExpr), subExpr->
getType(), destTy,
1995 case CK_IntegralToBoolean:
1996 return emitIntToBoolConversion(Visit(subExpr),
1999 case CK_PointerToBoolean:
2000 return emitPointerToBoolConversion(Visit(subExpr), subExpr->
getType());
2001 case CK_FloatingToBoolean:
2002 return emitFloatToBoolConversion(Visit(subExpr),
2004 case CK_MemberPointerToBoolean: {
2005 mlir::Value memPtr = Visit(subExpr);
2007 cir::CastKind::member_ptr_to_bool, memPtr,
2011 case CK_VectorSplat: {
2013 assert(destTy->
isVectorType() &&
"CK_VectorSplat to non-vector type");
2014 return builder.create<cir::VecSplatOp>(
2018 case CK_FunctionToPointerDecay:
2028mlir::Value ScalarExprEmitter::VisitCallExpr(
const CallExpr *e) {
2030 return emitLoadOfLValue(e);
2037mlir::Value ScalarExprEmitter::VisitMemberExpr(MemberExpr *e) {
2042 Expr::EvalResult result;
2047 return emitLoadOfLValue(e);
2050mlir::Value ScalarExprEmitter::VisitInitListExpr(InitListExpr *e) {
2051 const unsigned numInitElements = e->
getNumInits();
2059 const auto vectorType =
2062 SmallVector<mlir::Value, 16> elements;
2063 for (Expr *init : e->
inits()) {
2064 elements.push_back(Visit(init));
2068 if (numInitElements < vectorType.getSize()) {
2071 std::fill_n(std::back_inserter(elements),
2072 vectorType.getSize() - numInitElements, zeroValue);
2075 return cgf.
getBuilder().create<cir::VecCreateOp>(
2080 if (numInitElements == 0)
2091 "Invalid scalar expression to emit");
2093 .emitScalarConversion(src, srcTy, dstTy, loc);
2101 "Invalid complex -> scalar conversion");
2106 ? cir::CastKind::float_complex_to_bool
2107 : cir::CastKind::int_complex_to_bool;
2112 ? cir::CastKind::float_complex_to_real
2113 : cir::CastKind::int_complex_to_real;
2119mlir::Value ScalarExprEmitter::VisitUnaryLNot(
const UnaryOperator *e) {
2126 auto operVecTy = mlir::cast<cir::VectorType>(oper.getType());
2128 mlir::Value zeroVec = builder.getNullValue(operVecTy, loc);
2129 return cir::VecCmpOp::create(builder, loc, exprVecTy, cir::CmpOpKind::eq,
2137 boolVal = builder.createNot(boolVal);
2143mlir::Value ScalarExprEmitter::VisitUnaryReal(
const UnaryOperator *e) {
2145 mlir::Value result = VisitRealImag(e, promotionTy);
2146 if (result && !promotionTy.
isNull())
2147 result = emitUnPromotedValue(result, e->
getType());
2151mlir::Value ScalarExprEmitter::VisitUnaryImag(
const UnaryOperator *e) {
2153 mlir::Value result = VisitRealImag(e, promotionTy);
2154 if (result && !promotionTy.
isNull())
2155 result = emitUnPromotedValue(result, e->
getType());
2159mlir::Value ScalarExprEmitter::VisitRealImag(
const UnaryOperator *e,
2160 QualType promotionTy) {
2161 assert(e->
getOpcode() == clang::UO_Real ||
2163 "Invalid UnaryOp kind for ComplexType Real or Imag");
2180 ? builder.createComplexReal(loc, complex)
2181 : builder.createComplexImag(loc, complex);
2185 mlir::Value operand = promotionTy.
isNull()
2187 : cgf.emitPromotedScalarExpr(op, promotionTy);
2188 return builder.createComplexReal(loc, operand);
2193 mlir::Value operand;
2196 operand = cir::LoadOp::create(builder, loc, operand);
2197 }
else if (!promotionTy.
isNull()) {
2202 return builder.createComplexImag(loc, operand);
2207mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
2208 const UnaryExprOrTypeTraitExpr *e) {
2212 kind == UETT_SizeOf || kind == UETT_DataSizeOf) {
2215 "sizeof operator for VariableArrayType",
2217 return builder.getConstant(
2219 llvm::APSInt(llvm::APInt(64, 1),
true)));
2221 }
else if (e->
getKind() == UETT_OpenMPRequiredSimdAlign) {
2223 e->
getSourceRange(),
"sizeof operator for OpenMpRequiredSimdAlign",
2225 return builder.getConstant(
2227 llvm::APSInt(llvm::APInt(64, 1),
true)));
2230 return builder.getConstant(
2252mlir::Value ScalarExprEmitter::VisitAbstractConditionalOperator(
2253 const AbstractConditionalOperator *e) {
2256 ignoreResultAssign =
false;
2259 CIRGenFunction::OpaqueValueMapping binding(cgf, e);
2261 Expr *condExpr = e->
getCond();
2269 Expr *live = lhsExpr, *dead = rhsExpr;
2271 std::swap(live, dead);
2277 mlir::Value result = Visit(live);
2284 "throw expression in conditional operator");
2292 QualType condType = condExpr->
getType();
2305 cgf.
cgm.
errorNYI(loc,
"TernaryOp for SVE vector");
2309 mlir::Value condValue = Visit(condExpr);
2310 mlir::Value lhsValue = Visit(lhsExpr);
2311 mlir::Value rhsValue = Visit(rhsExpr);
2312 return builder.create<cir::VecTernaryOp>(loc, condValue, lhsValue,
2321 bool lhsIsVoid =
false;
2325 mlir::Value lhs = Visit(lhsExpr);
2331 mlir::Value rhs = Visit(rhsExpr);
2333 assert(!rhs &&
"lhs and rhs types must match");
2341 CIRGenFunction::ConditionalEvaluation eval(cgf);
2342 SmallVector<mlir::OpBuilder::InsertPoint, 2> insertPoints{};
2343 mlir::Type yieldTy{};
2345 auto emitBranch = [&](mlir::OpBuilder &
b, mlir::Location loc, Expr *
expr) {
2346 CIRGenFunction::LexicalScope lexScope{cgf, loc,
b.getInsertionBlock()};
2350 eval.beginEvaluation();
2351 mlir::Value branch = Visit(
expr);
2352 eval.endEvaluation();
2355 yieldTy = branch.getType();
2356 b.create<cir::YieldOp>(loc, branch);
2360 insertPoints.push_back(
b.saveInsertionPoint());
2364 mlir::Value result = builder
2365 .create<cir::TernaryOp>(
2368 [&](mlir::OpBuilder &
b, mlir::Location loc) {
2369 emitBranch(
b, loc, lhsExpr);
2372 [&](mlir::OpBuilder &
b, mlir::Location loc) {
2373 emitBranch(
b, loc, rhsExpr);
2377 if (!insertPoints.empty()) {
2383 for (mlir::OpBuilder::InsertPoint &toInsert : insertPoints) {
2384 mlir::OpBuilder::InsertionGuard guard(builder);
2385 builder.restoreInsertionPoint(toInsert);
2388 if (mlir::isa<cir::VoidType>(yieldTy)) {
2389 builder.create<cir::YieldOp>(loc);
2392 builder.create<cir::YieldOp>(loc, op0);
2402 cir::UnaryOpKind kind,
2405 .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.
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
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.
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)
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
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 scalableVectors()
static bool emitLValueAlignmentAssumption()
static bool incrementProfileCounter()
bool has(SanitizerMask K) const
Check if a certain (single) sanitizer is enabled.