================ @@ -92,6 +92,222 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { mlir::Value VisitCastExpr(CastExpr *E); + // Unary Operators. + mlir::Value VisitUnaryPostDec(const UnaryOperator *e) { + LValue lv = cgf.emitLValue(e->getSubExpr()); + return emitScalarPrePostIncDec(e, lv, false, false); + } + mlir::Value VisitUnaryPostInc(const UnaryOperator *e) { + LValue lv = cgf.emitLValue(e->getSubExpr()); + return emitScalarPrePostIncDec(e, lv, true, false); + } + mlir::Value VisitUnaryPreDec(const UnaryOperator *e) { + LValue lv = cgf.emitLValue(e->getSubExpr()); + return emitScalarPrePostIncDec(e, lv, false, true); + } + mlir::Value VisitUnaryPreInc(const UnaryOperator *e) { + LValue lv = cgf.emitLValue(e->getSubExpr()); + return emitScalarPrePostIncDec(e, lv, true, true); + } + mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv, + bool isInc, bool isPre) { + if (cgf.getLangOpts().OpenMP) + cgf.cgm.errorNYI(e->getSourceRange(), "inc/dec OpenMP"); + + QualType type = e->getSubExpr()->getType(); + + mlir::Value value; + mlir::Value input; + + if (type->getAs<AtomicType>()) { + cgf.cgm.errorNYI(e->getSourceRange(), "Atomic inc/dec"); + // TODO(cir): This is not correct, but it will produce reasonable code + // until atomic operations are implemented. + value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getScalarVal(); + input = value; + } else { + value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getScalarVal(); + input = value; + } + + // NOTE: When possible, more frequent cases are handled first. + + // Special case of integer increment that we have to check first: bool++. + // Due to promotion rules, we get: + // bool++ -> bool = bool + 1 + // -> bool = (int)bool + 1 + // -> bool = ((int)bool + 1 != 0) + // An interesting aspect of this is that increment is always true. + // Decrement does not have this property. + if (isInc && type->isBooleanType()) { + value = builder.create<cir::ConstantOp>(cgf.getLoc(e->getExprLoc()), + cgf.convertType(type), + builder.getCIRBoolAttr(true)); + } else if (type->isIntegerType()) { + QualType promotedType; + bool canPerformLossyDemotionCheck = false; + if (cgf.getContext().isPromotableIntegerType(type)) { + promotedType = cgf.getContext().getPromotedIntegerType(type); + assert(promotedType != type && "Shouldn't promote to the same type."); + canPerformLossyDemotionCheck = true; + canPerformLossyDemotionCheck &= + cgf.getContext().getCanonicalType(type) != + cgf.getContext().getCanonicalType(promotedType); + canPerformLossyDemotionCheck &= + type->isIntegerType() && promotedType->isIntegerType(); + + // TODO(cir): Currently, we store bitwidths in CIR types only for + // integers. This might also be required for other types. + auto srcCirTy = mlir::dyn_cast<cir::IntType>(cgf.convertType(type)); + auto promotedCirTy = + mlir::dyn_cast<cir::IntType>(cgf.convertType(type)); + assert(srcCirTy && promotedCirTy && "Expected integer type"); + + assert( + (!canPerformLossyDemotionCheck || + type->isSignedIntegerOrEnumerationType() || + promotedType->isSignedIntegerOrEnumerationType() || + srcCirTy.getWidth() == promotedCirTy.getWidth()) && + "The following check expects that if we do promotion to different " + "underlying canonical type, at least one of the types (either " + "base or promoted) will be signed, or the bitwidths will match."); + } + + assert(!cir::MissingFeatures::sanitizers()); + if (e->canOverflow() && type->isSignedIntegerOrEnumerationType()) { + value = emitIncDecConsiderOverflowBehavior(e, value, isInc); + } else { + cir::UnaryOpKind kind = + e->isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec; + // NOTE(CIR): clang calls CreateAdd but folds this to a unary op + value = emitUnaryOp(e, kind, input); + } + } else if (const PointerType *ptr = type->getAs<PointerType>()) { + cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec pointer"); + return {}; + } else if (type->isVectorType()) { + cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec vector"); + return {}; + } else if (type->isRealFloatingType()) { + assert(!cir::MissingFeatures::CGFPOptionsRAII()); + + if (type->isHalfType() && + !cgf.getContext().getLangOpts().NativeHalfType) { + cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec half"); + return {}; + } + + if (mlir::isa<cir::SingleType, cir::DoubleType>(value.getType())) { + // Create the inc/dec operation. + // NOTE(CIR): clang calls CreateAdd but folds this to a unary op + cir::UnaryOpKind kind = + (isInc ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec); + value = emitUnaryOp(e, kind, value); + } else { + cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec other fp type"); + return {}; + } + } else if (type->isFixedPointType()) { + cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec other fixed point"); + return {}; + } else { + assert(type->castAs<ObjCObjectPointerType>()); + cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec ObjectiveC pointer"); + return {}; + } + + CIRGenFunction::SourceLocRAIIObject sourceloc{ + cgf, cgf.getLoc(e->getSourceRange())}; + + // Store the updated result through the lvalue + if (lv.isBitField()) { + cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec bitfield"); + return {}; + } else { + cgf.emitStoreThroughLValue(RValue::get(value), lv); + } + + // If this is a postinc, return the value read from memory, otherwise use + // the updated value. + return isPre ? value : input; ---------------- erichkeane wrote:
Ah, I see... https://github.com/llvm/llvm-project/pull/131369 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits