================ @@ -558,8 +624,225 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { return res; } + + BinOpInfo emitBinOps(const BinaryOperator *e, + QualType promotionType = QualType()) { + BinOpInfo result; + result.lhs = cgf.emitPromotedScalarExpr(e->getLHS(), promotionType); + result.rhs = cgf.emitPromotedScalarExpr(e->getRHS(), promotionType); + if (!promotionType.isNull()) + result.fullType = promotionType; + else + result.fullType = e->getType(); + result.compType = result.fullType; + if (const auto *vecType = dyn_cast_or_null<VectorType>(result.fullType)) { + result.compType = vecType->getElementType(); + } + result.opcode = e->getOpcode(); + result.loc = e->getSourceRange(); + // TODO(cir): Result.FPFeatures + assert(!cir::MissingFeatures::getFPFeaturesInEffect()); + result.e = e; + return result; + } + + mlir::Value emitMul(const BinOpInfo &ops); + mlir::Value emitDiv(const BinOpInfo &ops); + mlir::Value emitRem(const BinOpInfo &ops); + mlir::Value emitAdd(const BinOpInfo &ops); + mlir::Value emitSub(const BinOpInfo &ops); + mlir::Value emitShl(const BinOpInfo &ops); + mlir::Value emitShr(const BinOpInfo &ops); + mlir::Value emitAnd(const BinOpInfo &ops); + mlir::Value emitXor(const BinOpInfo &ops); + mlir::Value emitOr(const BinOpInfo &ops); + + LValue emitCompoundAssignLValue( + const CompoundAssignOperator *e, + mlir::Value (ScalarExprEmitter::*f)(const BinOpInfo &), + mlir::Value &result); + mlir::Value + emitCompoundAssign(const CompoundAssignOperator *e, + mlir::Value (ScalarExprEmitter::*f)(const BinOpInfo &)); + + // TODO(cir): Candidate to be in a common AST helper between CIR and LLVM + // codegen. + QualType getPromotionType(QualType ty) { + if (ty->getAs<ComplexType>()) { + assert(!cir::MissingFeatures::complexType()); + cgf.cgm.errorNYI("promotion to complex type"); + return QualType(); + } + if (ty.UseExcessPrecision(cgf.getContext())) { + if (ty->getAs<VectorType>()) { + assert(!cir::MissingFeatures::vectorType()); + cgf.cgm.errorNYI("promotion to vector type"); + return QualType(); + } + return cgf.getContext().FloatTy; + } + return QualType(); + } + +// Binary operators and binary compound assignment operators. +#define HANDLEBINOP(OP) \ + mlir::Value VisitBin##OP(const BinaryOperator *e) { \ + QualType promotionTy = getPromotionType(e->getType()); \ + auto result = emit##OP(emitBinOps(e, promotionTy)); \ + if (result && !promotionTy.isNull()) \ + result = emitUnPromotedValue(result, e->getType()); \ + return result; \ + } \ + mlir::Value VisitBin##OP##Assign(const CompoundAssignOperator *e) { \ + return emitCompoundAssign(e, &ScalarExprEmitter::emit##OP); \ + } + + HANDLEBINOP(Mul) + HANDLEBINOP(Div) + HANDLEBINOP(Rem) + HANDLEBINOP(Add) + HANDLEBINOP(Sub) + HANDLEBINOP(Shl) + HANDLEBINOP(Shr) + HANDLEBINOP(And) + HANDLEBINOP(Xor) + HANDLEBINOP(Or) +#undef HANDLEBINOP }; +LValue ScalarExprEmitter::emitCompoundAssignLValue( + const CompoundAssignOperator *e, + mlir::Value (ScalarExprEmitter::*func)(const BinOpInfo &), + mlir::Value &result) { + QualType lhsTy = e->getLHS()->getType(); + BinOpInfo opInfo; + + if (e->getComputationResultType()->isAnyComplexType()) { + cgf.cgm.errorNYI(result.getLoc(), "complex lvalue assign"); + return LValue(); + } + + // Emit the RHS first. __block variables need to have the rhs evaluated + // first, plus this should improve codegen a little. + + QualType promotionTypeCR = getPromotionType(e->getComputationResultType()); + if (promotionTypeCR.isNull()) + promotionTypeCR = e->getComputationResultType(); + + QualType promotionTypeLHS = getPromotionType(e->getComputationLHSType()); + QualType promotionTypeRHS = getPromotionType(e->getRHS()->getType()); + + if (!promotionTypeRHS.isNull()) + opInfo.rhs = cgf.emitPromotedScalarExpr(e->getRHS(), promotionTypeRHS); + else + opInfo.rhs = Visit(e->getRHS()); + + opInfo.fullType = promotionTypeCR; + opInfo.compType = opInfo.fullType; + if (const auto *vecType = dyn_cast_or_null<VectorType>(opInfo.fullType)) { + opInfo.compType = vecType->getElementType(); + } + opInfo.opcode = e->getOpcode(); + opInfo.fpfeatures = e->getFPFeaturesInEffect(cgf.getLangOpts()); + opInfo.e = e; + opInfo.loc = e->getSourceRange(); + + // Load/convert the LHS + LValue lhsLV = cgf.emitLValue(e->getLHS()); + + if (lhsTy->getAs<AtomicType>()) { + cgf.cgm.errorNYI(result.getLoc(), "atomic lvalue assign"); + return LValue(); + } + + opInfo.lhs = emitLoadOfLValue(lhsLV, e->getExprLoc()); + + CIRGenFunction::SourceLocRAIIObject sourceloc{ + cgf, cgf.getLoc(e->getSourceRange())}; + SourceLocation loc = e->getExprLoc(); + if (!promotionTypeLHS.isNull()) + opInfo.lhs = emitScalarConversion(opInfo.lhs, lhsTy, promotionTypeLHS, + e->getExprLoc()); + else + opInfo.lhs = emitScalarConversion(opInfo.lhs, lhsTy, + e->getComputationLHSType(), loc); + + // Expand the binary operator. + result = (this->*func)(opInfo); + + // Convert the result back to the LHS type, + // potentially with Implicit Conversion sanitizer check. + result = emitScalarConversion(result, promotionTypeCR, lhsTy, loc); + // ScalarConversionOpts(cgf.sanOpts)); + + // Store the result value into the LHS lvalue. Bit-fields are handled + // specially because the result is altered by the store, i.e., [C99 6.5.16p1] + // 'An assignment expression has the value of the left operand after the + // assignment...'. + if (lhsLV.isBitField()) + cgf.cgm.errorNYI(e->getSourceRange(), "store through bitfield lvalue"); + else + cgf.emitStoreThroughLValue(RValue::get(result), lhsLV); + + if (cgf.getLangOpts().OpenMP) + cgf.cgm.errorNYI(e->getSourceRange(), "openmp"); + + return lhsLV; +} + +mlir::Value ScalarExprEmitter::emitPromoted(const Expr *e, + QualType promotionType) { + e = e->IgnoreParens(); + if (const auto *bo = dyn_cast<BinaryOperator>(e)) { + switch (bo->getOpcode()) { +#define HANDLE_BINOP(OP) \ + case BO_##OP: \ + return emit##OP(emitBinOps(bo, promotionType)); + HANDLE_BINOP(Add) + HANDLE_BINOP(Sub) + HANDLE_BINOP(Mul) + HANDLE_BINOP(Div) +#undef HANDLE_BINOP + default: + break; + } + } else if (isa<UnaryOperator>(e)) { + cgf.cgm.errorNYI(e->getSourceRange(), "unary operators"); + return {}; + } + mlir::Value result = Visit(const_cast<Expr *>(e)); + if (result) { + if (!promotionType.isNull()) + return emitPromotedValue(result, promotionType); + return emitUnPromotedValue(result, e->getType()); + } + return result; +} + +mlir::Value ScalarExprEmitter::emitCompoundAssign( + const CompoundAssignOperator *e, + mlir::Value (ScalarExprEmitter::*func)(const BinOpInfo &)) { + + bool ignore = std::exchange(ignoreResultAssign, false); ---------------- andykaylor wrote:
Nice! https://github.com/llvm/llvm-project/pull/132420 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits