| #include "CIRGenBuilder.h" |
| #include "CIRGenFunction.h" |
| |
| #include "clang/AST/StmtVisitor.h" |
| |
| using namespace clang; |
| using namespace clang::CIRGen; |
| |
| #ifndef NDEBUG |
| /// Return the complex type that we are meant to emit. |
| static const ComplexType *getComplexType(QualType type) { |
| type = type.getCanonicalType(); |
| if (const ComplexType *comp = dyn_cast<ComplexType>(type)) |
| return comp; |
| return cast<ComplexType>(cast<AtomicType>(type)->getValueType()); |
| } |
| #endif // NDEBUG |
| |
| namespace { |
| class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> { |
| CIRGenFunction &cgf; |
| CIRGenBuilderTy &builder; |
| |
| public: |
| explicit ComplexExprEmitter(CIRGenFunction &cgf) |
| : cgf(cgf), builder(cgf.getBuilder()) {} |
| |
| //===--------------------------------------------------------------------===// |
| // Utilities |
| //===--------------------------------------------------------------------===// |
| |
| /// Given an expression with complex type that represents a value l-value, |
| /// this method emits the address of the l-value, then loads and returns the |
| /// result. |
| mlir::Value emitLoadOfLValue(const Expr *e) { |
| return emitLoadOfLValue(cgf.emitLValue(e), e->getExprLoc()); |
| } |
| |
| mlir::Value emitLoadOfLValue(LValue lv, SourceLocation loc); |
| |
| /// Store the specified real/imag parts into the |
| /// specified value pointer. |
| void emitStoreOfComplex(mlir::Location loc, mlir::Value val, LValue lv, |
| bool isInit); |
| |
| /// Emit a cast from complex value Val to DestType. |
| mlir::Value emitComplexToComplexCast(mlir::Value value, QualType srcType, |
| QualType destType, SourceLocation loc); |
| |
| /// Emit a cast from scalar value Val to DestType. |
| mlir::Value emitScalarToComplexCast(mlir::Value value, QualType srcType, |
| QualType destType, SourceLocation loc); |
| |
| //===--------------------------------------------------------------------===// |
| // Visitor Methods |
| //===--------------------------------------------------------------------===// |
| |
| mlir::Value Visit(Expr *e) { |
| return StmtVisitor<ComplexExprEmitter, mlir::Value>::Visit(e); |
| } |
| |
| mlir::Value VisitStmt(Stmt *s) { |
| cgf.cgm.errorNYI(s->getBeginLoc(), "ComplexExprEmitter VisitStmt"); |
| return {}; |
| } |
| |
| mlir::Value VisitExpr(Expr *e); |
| mlir::Value VisitConstantExpr(ConstantExpr *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitConstantExpr"); |
| return {}; |
| } |
| |
| mlir::Value VisitParenExpr(ParenExpr *pe) { return Visit(pe->getSubExpr()); } |
| mlir::Value VisitGenericSelectionExpr(GenericSelectionExpr *ge) { |
| return Visit(ge->getResultExpr()); |
| } |
| mlir::Value VisitImaginaryLiteral(const ImaginaryLiteral *il); |
| mlir::Value |
| VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *pe) { |
| return Visit(pe->getReplacement()); |
| } |
| mlir::Value VisitCoawaitExpr(CoawaitExpr *s) { |
| cgf.cgm.errorNYI(s->getExprLoc(), "ComplexExprEmitter VisitCoawaitExpr"); |
| return {}; |
| } |
| mlir::Value VisitCoyieldExpr(CoyieldExpr *s) { |
| cgf.cgm.errorNYI(s->getExprLoc(), "ComplexExprEmitter VisitCoyieldExpr"); |
| return {}; |
| } |
| mlir::Value VisitUnaryCoawait(const UnaryOperator *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitUnaryCoawait"); |
| return {}; |
| } |
| |
| mlir::Value emitConstant(const CIRGenFunction::ConstantEmission &constant, |
| Expr *e) { |
| assert(constant && "not a constant"); |
| if (constant.isReference()) |
| return emitLoadOfLValue(constant.getReferenceLValue(cgf, e), |
| e->getExprLoc()); |
| |
| mlir::TypedAttr valueAttr = constant.getValue(); |
| return builder.getConstant(cgf.getLoc(e->getSourceRange()), valueAttr); |
| } |
| |
| // l-values. |
| mlir::Value VisitDeclRefExpr(DeclRefExpr *e) { |
| if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(e)) |
| return emitConstant(constant, e); |
| return emitLoadOfLValue(e); |
| } |
| mlir::Value VisitObjCIvarRefExpr(ObjCIvarRefExpr *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), |
| "ComplexExprEmitter VisitObjCIvarRefExpr"); |
| return {}; |
| } |
| mlir::Value VisitObjCMessageExpr(ObjCMessageExpr *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), |
| "ComplexExprEmitter VisitObjCMessageExpr"); |
| return {}; |
| } |
| mlir::Value VisitArraySubscriptExpr(Expr *e) { return emitLoadOfLValue(e); } |
| mlir::Value VisitMemberExpr(MemberExpr *me) { |
| if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(me)) { |
| cgf.emitIgnoredExpr(me->getBase()); |
| return emitConstant(constant, me); |
| } |
| return emitLoadOfLValue(me); |
| } |
| mlir::Value VisitOpaqueValueExpr(OpaqueValueExpr *e) { |
| if (e->isGLValue()) |
| return emitLoadOfLValue(cgf.getOrCreateOpaqueLValueMapping(e), |
| e->getExprLoc()); |
| |
| // Otherwise, assume the mapping is the scalar directly. |
| return cgf.getOrCreateOpaqueRValueMapping(e).getValue(); |
| } |
| |
| mlir::Value VisitPseudoObjectExpr(PseudoObjectExpr *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), |
| "ComplexExprEmitter VisitPseudoObjectExpr"); |
| return {}; |
| } |
| |
| mlir::Value emitCast(CastKind ck, Expr *op, QualType destTy); |
| mlir::Value VisitImplicitCastExpr(ImplicitCastExpr *e) { |
| // Unlike for scalars, we don't have to worry about function->ptr demotion |
| // here. |
| if (e->changesVolatileQualification()) |
| return emitLoadOfLValue(e); |
| return emitCast(e->getCastKind(), e->getSubExpr(), e->getType()); |
| } |
| mlir::Value VisitCastExpr(CastExpr *e) { |
| if (const auto *ece = dyn_cast<ExplicitCastExpr>(e)) { |
| // Bind VLAs in the cast type. |
| if (ece->getType()->isVariablyModifiedType()) { |
| cgf.cgm.errorNYI(e->getExprLoc(), |
| "VisitCastExpr Bind VLAs in the cast type"); |
| return {}; |
| } |
| } |
| |
| if (e->changesVolatileQualification()) |
| return emitLoadOfLValue(e); |
| |
| return emitCast(e->getCastKind(), e->getSubExpr(), e->getType()); |
| } |
| mlir::Value VisitCallExpr(const CallExpr *e); |
| mlir::Value VisitStmtExpr(const StmtExpr *e); |
| |
| // Operators. |
| mlir::Value VisitPrePostIncDec(const UnaryOperator *e, cir::UnaryOpKind op, |
| bool isPre) { |
| LValue lv = cgf.emitLValue(e->getSubExpr()); |
| return cgf.emitComplexPrePostIncDec(e, lv, op, isPre); |
| } |
| mlir::Value VisitUnaryPostDec(const UnaryOperator *e) { |
| return VisitPrePostIncDec(e, cir::UnaryOpKind::Dec, false); |
| } |
| mlir::Value VisitUnaryPostInc(const UnaryOperator *e) { |
| return VisitPrePostIncDec(e, cir::UnaryOpKind::Inc, false); |
| } |
| mlir::Value VisitUnaryPreDec(const UnaryOperator *e) { |
| return VisitPrePostIncDec(e, cir::UnaryOpKind::Dec, true); |
| } |
| mlir::Value VisitUnaryPreInc(const UnaryOperator *e) { |
| return VisitPrePostIncDec(e, cir::UnaryOpKind::Inc, true); |
| } |
| mlir::Value VisitUnaryDeref(const Expr *e) { return emitLoadOfLValue(e); } |
| |
| mlir::Value VisitUnaryPlus(const UnaryOperator *e); |
| mlir::Value VisitUnaryMinus(const UnaryOperator *e); |
| mlir::Value VisitPlusMinus(const UnaryOperator *e, cir::UnaryOpKind kind, |
| QualType promotionType); |
| mlir::Value VisitUnaryNot(const UnaryOperator *e); |
| // LNot,Real,Imag never return complex. |
| mlir::Value VisitUnaryExtension(const UnaryOperator *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitUnaryExtension"); |
| return {}; |
| } |
| mlir::Value VisitCXXDefaultArgExpr(CXXDefaultArgExpr *dae) { |
| cgf.cgm.errorNYI(dae->getExprLoc(), |
| "ComplexExprEmitter VisitCXXDefaultArgExpr"); |
| return {}; |
| } |
| mlir::Value VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) { |
| CIRGenFunction::CXXDefaultInitExprScope scope(cgf, die); |
| return Visit(die->getExpr()); |
| } |
| mlir::Value VisitExprWithCleanups(ExprWithCleanups *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), |
| "ComplexExprEmitter VisitExprWithCleanups"); |
| return {}; |
| } |
| mlir::Value VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *e) { |
| mlir::Location loc = cgf.getLoc(e->getExprLoc()); |
| mlir::Type complexTy = cgf.convertType(e->getType()); |
| return builder.getNullValue(complexTy, loc); |
| } |
| mlir::Value VisitImplicitValueInitExpr(ImplicitValueInitExpr *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), |
| "ComplexExprEmitter VisitImplicitValueInitExpr"); |
| return {}; |
| } |
| |
| struct BinOpInfo { |
| mlir::Location loc; |
| mlir::Value lhs{}; |
| mlir::Value rhs{}; |
| QualType ty{}; // Computation Type. |
| FPOptions fpFeatures{}; |
| }; |
| |
| BinOpInfo emitBinOps(const BinaryOperator *e, |
| QualType promotionTy = QualType()); |
| |
| mlir::Value emitPromoted(const Expr *e, QualType promotionTy); |
| mlir::Value emitPromotedComplexOperand(const Expr *e, QualType promotionTy); |
| LValue emitCompoundAssignLValue( |
| const CompoundAssignOperator *e, |
| mlir::Value (ComplexExprEmitter::*func)(const BinOpInfo &), |
| RValue &value); |
| mlir::Value emitCompoundAssign( |
| const CompoundAssignOperator *e, |
| mlir::Value (ComplexExprEmitter::*func)(const BinOpInfo &)); |
| |
| mlir::Value emitBinAdd(const BinOpInfo &op); |
| mlir::Value emitBinSub(const BinOpInfo &op); |
| mlir::Value emitBinMul(const BinOpInfo &op); |
| mlir::Value emitBinDiv(const BinOpInfo &op); |
| |
| QualType getPromotionType(QualType ty, bool isDivOpCode = false) { |
| if (auto *complexTy = ty->getAs<ComplexType>()) { |
| QualType elementTy = complexTy->getElementType(); |
| if (elementTy.UseExcessPrecision(cgf.getContext())) |
| return cgf.getContext().getComplexType(cgf.getContext().FloatTy); |
| } |
| |
| if (ty.UseExcessPrecision(cgf.getContext())) |
| return cgf.getContext().FloatTy; |
| return QualType(); |
| } |
| |
| #define HANDLEBINOP(OP) \ |
| mlir::Value VisitBin##OP(const BinaryOperator *e) { \ |
| QualType promotionTy = getPromotionType( \ |
| e->getType(), e->getOpcode() == BinaryOperatorKind::BO_Div); \ |
| mlir::Value result = emitBin##OP(emitBinOps(e, promotionTy)); \ |
| if (!promotionTy.isNull()) \ |
| result = cgf.emitUnPromotedValue(result, e->getType()); \ |
| return result; \ |
| } |
| |
| HANDLEBINOP(Add) |
| HANDLEBINOP(Sub) |
| HANDLEBINOP(Mul) |
| HANDLEBINOP(Div) |
| #undef HANDLEBINOP |
| |
| mlir::Value VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), |
| "ComplexExprEmitter VisitCXXRewrittenBinaryOperator"); |
| return {}; |
| } |
| |
| // Compound assignments. |
| mlir::Value VisitBinAddAssign(const CompoundAssignOperator *e) { |
| return emitCompoundAssign(e, &ComplexExprEmitter::emitBinAdd); |
| } |
| mlir::Value VisitBinSubAssign(const CompoundAssignOperator *e) { |
| return emitCompoundAssign(e, &ComplexExprEmitter::emitBinSub); |
| } |
| mlir::Value VisitBinMulAssign(const CompoundAssignOperator *e) { |
| return emitCompoundAssign(e, &ComplexExprEmitter::emitBinMul); |
| } |
| mlir::Value VisitBinDivAssign(const CompoundAssignOperator *e) { |
| return emitCompoundAssign(e, &ComplexExprEmitter::emitBinDiv); |
| } |
| |
| // GCC rejects rem/and/or/xor for integer complex. |
| // Logical and/or always return int, never complex. |
| |
| // No comparisons produce a complex result. |
| |
| LValue emitBinAssignLValue(const BinaryOperator *e, mlir::Value &val); |
| mlir::Value VisitBinAssign(const BinaryOperator *e); |
| mlir::Value VisitBinComma(const BinaryOperator *e); |
| |
| mlir::Value |
| VisitAbstractConditionalOperator(const AbstractConditionalOperator *e); |
| mlir::Value VisitChooseExpr(ChooseExpr *e); |
| |
| mlir::Value VisitInitListExpr(InitListExpr *e); |
| |
| mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *e) { |
| return emitLoadOfLValue(e); |
| } |
| |
| mlir::Value VisitVAArgExpr(VAArgExpr *e); |
| |
| mlir::Value VisitAtomicExpr(AtomicExpr *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitAtomicExpr"); |
| return {}; |
| } |
| |
| mlir::Value VisitPackIndexingExpr(PackIndexingExpr *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), |
| "ComplexExprEmitter VisitPackIndexingExpr"); |
| return {}; |
| } |
| }; |
| } // namespace |
| |
| //===----------------------------------------------------------------------===// |
| // Utilities |
| //===----------------------------------------------------------------------===// |
| |
| /// EmitLoadOfLValue - Given an RValue reference for a complex, emit code to |
| /// load the real and imaginary pieces, returning them as Real/Imag. |
| mlir::Value ComplexExprEmitter::emitLoadOfLValue(LValue lv, |
| SourceLocation loc) { |
| assert(lv.isSimple() && "non-simple complex l-value?"); |
| if (lv.getType()->isAtomicType()) |
| cgf.cgm.errorNYI(loc, "emitLoadOfLValue with Atomic LV"); |
| |
| const Address srcAddr = lv.getAddress(); |
| return builder.createLoad(cgf.getLoc(loc), srcAddr); |
| } |
| |
| /// EmitStoreOfComplex - Store the specified real/imag parts into the |
| /// specified value pointer. |
| void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val, |
| LValue lv, bool isInit) { |
| if (lv.getType()->isAtomicType() || |
| (!isInit && cgf.isLValueSuitableForInlineAtomic(lv))) { |
| cgf.cgm.errorNYI(loc, "StoreOfComplex with Atomic LV"); |
| return; |
| } |
| |
| const Address destAddr = lv.getAddress(); |
| builder.createStore(loc, val, destAddr); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Visitor Methods |
| //===----------------------------------------------------------------------===// |
| |
| mlir::Value ComplexExprEmitter::VisitExpr(Expr *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitExpr"); |
| return {}; |
| } |
| |
| mlir::Value |
| ComplexExprEmitter::VisitImaginaryLiteral(const ImaginaryLiteral *il) { |
| auto ty = mlir::cast<cir::ComplexType>(cgf.convertType(il->getType())); |
| mlir::Type elementTy = ty.getElementType(); |
| mlir::Location loc = cgf.getLoc(il->getExprLoc()); |
| |
| mlir::TypedAttr realValueAttr; |
| mlir::TypedAttr imagValueAttr; |
| |
| if (mlir::isa<cir::IntType>(elementTy)) { |
| llvm::APInt imagValue = cast<IntegerLiteral>(il->getSubExpr())->getValue(); |
| realValueAttr = cir::IntAttr::get(elementTy, 0); |
| imagValueAttr = cir::IntAttr::get(elementTy, imagValue); |
| } else { |
| assert(mlir::isa<cir::FPTypeInterface>(elementTy) && |
| "Expected complex element type to be floating-point"); |
| |
| llvm::APFloat imagValue = |
| cast<FloatingLiteral>(il->getSubExpr())->getValue(); |
| realValueAttr = cir::FPAttr::get( |
| elementTy, llvm::APFloat::getZero(imagValue.getSemantics())); |
| imagValueAttr = cir::FPAttr::get(elementTy, imagValue); |
| } |
| |
| auto complexAttr = cir::ConstComplexAttr::get(realValueAttr, imagValueAttr); |
| return builder.create<cir::ConstantOp>(loc, complexAttr); |
| } |
| |
| mlir::Value ComplexExprEmitter::VisitCallExpr(const CallExpr *e) { |
| if (e->getCallReturnType(cgf.getContext())->isReferenceType()) |
| return emitLoadOfLValue(e); |
| return cgf.emitCallExpr(e).getComplexValue(); |
| } |
| |
| mlir::Value ComplexExprEmitter::VisitStmtExpr(const StmtExpr *e) { |
| cgf.cgm.errorNYI(e->getExprLoc(), "ComplexExprEmitter VisitExpr"); |
| return {}; |
| } |
| |
| mlir::Value ComplexExprEmitter::emitComplexToComplexCast(mlir::Value val, |
| QualType srcType, |
| QualType destType, |
| SourceLocation loc) { |
| if (srcType == destType) |
| return val; |
| |
| // Get the src/dest element type. |
| QualType srcElemTy = srcType->castAs<ComplexType>()->getElementType(); |
| QualType destElemTy = destType->castAs<ComplexType>()->getElementType(); |
| |
| cir::CastKind castOpKind; |
| if (srcElemTy->isFloatingType() && destElemTy->isFloatingType()) |
| castOpKind = cir::CastKind::float_complex; |
| else if (srcElemTy->isFloatingType() && destElemTy->isIntegerType()) |
| castOpKind = cir::CastKind::float_complex_to_int_complex; |
| else if (srcElemTy->isIntegerType() && destElemTy->isFloatingType()) |
| castOpKind = cir::CastKind::int_complex_to_float_complex; |
| else if (srcElemTy->isIntegerType() && destElemTy->isIntegerType()) |
| castOpKind = cir::CastKind::int_complex; |
| else |
| llvm_unreachable("unexpected src type or dest type"); |
| |
| return builder.createCast(cgf.getLoc(loc), castOpKind, val, |
| cgf.convertType(destType)); |
| } |
| |
| mlir::Value ComplexExprEmitter::emitScalarToComplexCast(mlir::Value val, |
| QualType srcType, |
| QualType destType, |
| SourceLocation loc) { |
| cir::CastKind castOpKind; |
| if (srcType->isFloatingType()) |
| castOpKind = cir::CastKind::float_to_complex; |
| else if (srcType->isIntegerType()) |
| castOpKind = cir::CastKind::int_to_complex; |
| else |
| llvm_unreachable("unexpected src type"); |
| |
| return builder.createCast(cgf.getLoc(loc), castOpKind, val, |
| cgf.convertType(destType)); |
| } |
| |
| mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op, |
| QualType destTy) { |
| switch (ck) { |
| case CK_Dependent: |
| llvm_unreachable("dependent type must be resolved before the CIR codegen"); |
| |
| case CK_NoOp: |
| case CK_LValueToRValue: |
| return Visit(op); |
| |
| case CK_AtomicToNonAtomic: |
| case CK_NonAtomicToAtomic: |
| case CK_UserDefinedConversion: { |
| cgf.cgm.errorNYI( |
| "ComplexExprEmitter::emitCast Atmoic & UserDefinedConversion"); |
| return {}; |
| } |
| |
| case CK_LValueBitCast: { |
| LValue origLV = cgf.emitLValue(op); |
| Address addr = |
| origLV.getAddress().withElementType(builder, cgf.convertType(destTy)); |
| LValue destLV = cgf.makeAddrLValue(addr, destTy); |
| return emitLoadOfLValue(destLV, op->getExprLoc()); |
| } |
| |
| case CK_LValueToRValueBitCast: { |
| LValue sourceLVal = cgf.emitLValue(op); |
| Address addr = sourceLVal.getAddress().withElementType( |
| builder, cgf.convertTypeForMem(destTy)); |
| LValue destLV = cgf.makeAddrLValue(addr, destTy); |
| assert(!cir::MissingFeatures::opTBAA()); |
| return emitLoadOfLValue(destLV, op->getExprLoc()); |
| } |
| |
| case CK_BitCast: |
| case CK_BaseToDerived: |
| case CK_DerivedToBase: |
| case CK_UncheckedDerivedToBase: |
| case CK_Dynamic: |
| case CK_ToUnion: |
| case CK_ArrayToPointerDecay: |
| case CK_FunctionToPointerDecay: |
| case CK_NullToPointer: |
| case CK_NullToMemberPointer: |
| case CK_BaseToDerivedMemberPointer: |
| case CK_DerivedToBaseMemberPointer: |
| case CK_MemberPointerToBoolean: |
| case CK_ReinterpretMemberPointer: |
| case CK_ConstructorConversion: |
| case CK_IntegralToPointer: |
| case CK_PointerToIntegral: |
| case CK_PointerToBoolean: |
| case CK_ToVoid: |
| case CK_VectorSplat: |
| case CK_IntegralCast: |
| case CK_BooleanToSignedIntegral: |
| case CK_IntegralToBoolean: |
| case CK_IntegralToFloating: |
| case CK_FloatingToIntegral: |
| case CK_FloatingToBoolean: |
| case CK_FloatingCast: |
| case CK_CPointerToObjCPointerCast: |
| case CK_BlockPointerToObjCPointerCast: |
| case CK_AnyPointerToBlockPointerCast: |
| case CK_ObjCObjectLValueCast: |
| case CK_FloatingComplexToReal: |
| case CK_FloatingComplexToBoolean: |
| case CK_IntegralComplexToReal: |
| case CK_IntegralComplexToBoolean: |
| case CK_ARCProduceObject: |
| case CK_ARCConsumeObject: |
| case CK_ARCReclaimReturnedObject: |
| case CK_ARCExtendBlockObject: |
| case CK_CopyAndAutoreleaseBlockObject: |
| case CK_BuiltinFnToFnPtr: |
| case CK_ZeroToOCLOpaqueType: |
| case CK_AddressSpaceConversion: |
| case CK_IntToOCLSampler: |
| case CK_FloatingToFixedPoint: |
| case CK_FixedPointToFloating: |
| case CK_FixedPointCast: |
| case CK_FixedPointToBoolean: |
| case CK_FixedPointToIntegral: |
| case CK_IntegralToFixedPoint: |
| case CK_MatrixCast: |
| case CK_HLSLVectorTruncation: |
| case CK_HLSLArrayRValue: |
| case CK_HLSLElementwiseCast: |
| case CK_HLSLAggregateSplatCast: |
| llvm_unreachable("invalid cast kind for complex value"); |
| |
| case CK_FloatingRealToComplex: |
| case CK_IntegralRealToComplex: { |
| assert(!cir::MissingFeatures::cgFPOptionsRAII()); |
| return emitScalarToComplexCast(cgf.emitScalarExpr(op), op->getType(), |
| destTy, op->getExprLoc()); |
| } |
| |
| case CK_FloatingComplexCast: |
| case CK_FloatingComplexToIntegralComplex: |
| case CK_IntegralComplexCast: |
| case CK_IntegralComplexToFloatingComplex: { |
| assert(!cir::MissingFeatures::cgFPOptionsRAII()); |
| return emitComplexToComplexCast(Visit(op), op->getType(), destTy, |
| op->getExprLoc()); |
| } |
| } |
| |
| llvm_unreachable("unknown cast resulting in complex value"); |
| } |
| |
| mlir::Value ComplexExprEmitter::VisitUnaryPlus(const UnaryOperator *e) { |
| QualType promotionTy = getPromotionType(e->getSubExpr()->getType()); |
| mlir::Value result = VisitPlusMinus(e, cir::UnaryOpKind::Plus, promotionTy); |
| if (!promotionTy.isNull()) |
| return cgf.emitUnPromotedValue(result, e->getSubExpr()->getType()); |
| return result; |
| } |
| |
| mlir::Value ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *e) { |
| QualType promotionTy = getPromotionType(e->getSubExpr()->getType()); |
| mlir::Value result = VisitPlusMinus(e, cir::UnaryOpKind::Minus, promotionTy); |
| if (!promotionTy.isNull()) |
| return cgf.emitUnPromotedValue(result, e->getSubExpr()->getType()); |
| return result; |
| } |
| |
| mlir::Value ComplexExprEmitter::VisitPlusMinus(const UnaryOperator *e, |
| cir::UnaryOpKind kind, |
| QualType promotionType) { |
| assert(kind == cir::UnaryOpKind::Plus || |
| kind == cir::UnaryOpKind::Minus && |
| "Invalid UnaryOp kind for ComplexType Plus or Minus"); |
| |
| mlir::Value op; |
| if (!promotionType.isNull()) |
| op = cgf.emitPromotedComplexExpr(e->getSubExpr(), promotionType); |
| else |
| op = Visit(e->getSubExpr()); |
| return builder.createUnaryOp(cgf.getLoc(e->getExprLoc()), kind, op); |
| } |
| |
| mlir::Value ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *e) { |
| mlir::Value op = Visit(e->getSubExpr()); |
| return builder.createNot(op); |
| } |
| |
| mlir::Value ComplexExprEmitter::emitBinAdd(const BinOpInfo &op) { |
| assert(!cir::MissingFeatures::fastMathFlags()); |
| assert(!cir::MissingFeatures::cgFPOptionsRAII()); |
| |
| if (mlir::isa<cir::ComplexType>(op.lhs.getType()) && |
| mlir::isa<cir::ComplexType>(op.rhs.getType())) |
| return builder.create<cir::ComplexAddOp>(op.loc, op.lhs, op.rhs); |
| |
| if (mlir::isa<cir::ComplexType>(op.lhs.getType())) { |
| mlir::Value real = builder.createComplexReal(op.loc, op.lhs); |
| mlir::Value imag = builder.createComplexImag(op.loc, op.lhs); |
| mlir::Value newReal = builder.createAdd(op.loc, real, op.rhs); |
| return builder.createComplexCreate(op.loc, newReal, imag); |
| } |
| |
| assert(mlir::isa<cir::ComplexType>(op.rhs.getType())); |
| mlir::Value real = builder.createComplexReal(op.loc, op.rhs); |
| mlir::Value imag = builder.createComplexImag(op.loc, op.rhs); |
| mlir::Value newReal = builder.createAdd(op.loc, op.lhs, real); |
| return builder.createComplexCreate(op.loc, newReal, imag); |
| } |
| |
| mlir::Value ComplexExprEmitter::emitBinSub(const BinOpInfo &op) { |
| assert(!cir::MissingFeatures::fastMathFlags()); |
| assert(!cir::MissingFeatures::cgFPOptionsRAII()); |
| |
| if (mlir::isa<cir::ComplexType>(op.lhs.getType()) && |
| mlir::isa<cir::ComplexType>(op.rhs.getType())) |
| return builder.create<cir::ComplexSubOp>(op.loc, op.lhs, op.rhs); |
| |
| if (mlir::isa<cir::ComplexType>(op.lhs.getType())) { |
| mlir::Value real = builder.createComplexReal(op.loc, op.lhs); |
| mlir::Value imag = builder.createComplexImag(op.loc, op.lhs); |
| mlir::Value newReal = builder.createSub(op.loc, real, op.rhs); |
| return builder.createComplexCreate(op.loc, newReal, imag); |
| } |
| |
| assert(mlir::isa<cir::ComplexType>(op.rhs.getType())); |
| mlir::Value real = builder.createComplexReal(op.loc, op.rhs); |
| mlir::Value imag = builder.createComplexImag(op.loc, op.rhs); |
| mlir::Value newReal = builder.createSub(op.loc, op.lhs, real); |
| return builder.createComplexCreate(op.loc, newReal, imag); |
| } |
| |
| static cir::ComplexRangeKind |
| getComplexRangeAttr(LangOptions::ComplexRangeKind range) { |
| switch (range) { |
| case LangOptions::CX_Full: |
| return cir::ComplexRangeKind::Full; |
| case LangOptions::CX_Improved: |
| return cir::ComplexRangeKind::Improved; |
| case LangOptions::CX_Promoted: |
| return cir::ComplexRangeKind::Promoted; |
| case LangOptions::CX_Basic: |
| return cir::ComplexRangeKind::Basic; |
| case LangOptions::CX_None: |
| // The default value for ComplexRangeKind is Full if no option is selected |
| return cir::ComplexRangeKind::Full; |
| } |
| } |
| |
| mlir::Value ComplexExprEmitter::emitBinMul(const BinOpInfo &op) { |
| assert(!cir::MissingFeatures::fastMathFlags()); |
| assert(!cir::MissingFeatures::cgFPOptionsRAII()); |
| |
| if (mlir::isa<cir::ComplexType>(op.lhs.getType()) && |
| mlir::isa<cir::ComplexType>(op.rhs.getType())) { |
| cir::ComplexRangeKind rangeKind = |
| getComplexRangeAttr(op.fpFeatures.getComplexRange()); |
| return builder.create<cir::ComplexMulOp>(op.loc, op.lhs, op.rhs, rangeKind); |
| } |
| |
| if (mlir::isa<cir::ComplexType>(op.lhs.getType())) { |
| mlir::Value real = builder.createComplexReal(op.loc, op.lhs); |
| mlir::Value imag = builder.createComplexImag(op.loc, op.lhs); |
| mlir::Value newReal = builder.createMul(op.loc, real, op.rhs); |
| mlir::Value newImag = builder.createMul(op.loc, imag, op.rhs); |
| return builder.createComplexCreate(op.loc, newReal, newImag); |
| } |
| |
| assert(mlir::isa<cir::ComplexType>(op.rhs.getType())); |
| mlir::Value real = builder.createComplexReal(op.loc, op.rhs); |
| mlir::Value imag = builder.createComplexImag(op.loc, op.rhs); |
| mlir::Value newReal = builder.createMul(op.loc, op.lhs, real); |
| mlir::Value newImag = builder.createMul(op.loc, op.lhs, imag); |
| return builder.createComplexCreate(op.loc, newReal, newImag); |
| } |
| |
| mlir::Value ComplexExprEmitter::emitBinDiv(const BinOpInfo &op) { |
| assert(!cir::MissingFeatures::fastMathFlags()); |
| assert(!cir::MissingFeatures::cgFPOptionsRAII()); |
| |
| // Handle division between two complex values. In the case of complex integer |
| // types mixed with scalar integers, the scalar integer type will always be |
| // promoted to a complex integer value with a zero imaginary component when |
| // the AST is formed. |
| if (mlir::isa<cir::ComplexType>(op.lhs.getType()) && |
| mlir::isa<cir::ComplexType>(op.rhs.getType())) { |
| cir::ComplexRangeKind rangeKind = |
| getComplexRangeAttr(op.fpFeatures.getComplexRange()); |
| return cir::ComplexDivOp::create(builder, op.loc, op.lhs, op.rhs, |
| rangeKind); |
| } |
| |
| // The C99 standard (G.5.1) defines division of a complex value by a real |
| // value in the following simplified form. |
| if (mlir::isa<cir::ComplexType>(op.lhs.getType())) { |
| assert(mlir::cast<cir::ComplexType>(op.lhs.getType()).getElementType() == |
| op.rhs.getType()); |
| mlir::Value real = builder.createComplexReal(op.loc, op.lhs); |
| mlir::Value imag = builder.createComplexImag(op.loc, op.lhs); |
| mlir::Value newReal = builder.createFDiv(op.loc, real, op.rhs); |
| mlir::Value newImag = builder.createFDiv(op.loc, imag, op.rhs); |
| return builder.createComplexCreate(op.loc, newReal, newImag); |
| } |
| |
| assert(mlir::isa<cir::ComplexType>(op.rhs.getType())); |
| cir::ConstantOp nullValue = builder.getNullValue(op.lhs.getType(), op.loc); |
| mlir::Value lhs = builder.createComplexCreate(op.loc, op.lhs, nullValue); |
| cir::ComplexRangeKind rangeKind = |
| getComplexRangeAttr(op.fpFeatures.getComplexRange()); |
| return cir::ComplexDivOp::create(builder, op.loc, lhs, op.rhs, rangeKind); |
| } |
| |
| mlir::Value CIRGenFunction::emitUnPromotedValue(mlir::Value result, |
| QualType unPromotionType) { |
| assert(!mlir::cast<cir::ComplexType>(result.getType()).isIntegerComplex() && |
| "integral complex will never be promoted"); |
| return builder.createCast(cir::CastKind::float_complex, result, |
| convertType(unPromotionType)); |
| } |
| |
| mlir::Value CIRGenFunction::emitPromotedValue(mlir::Value result, |
| QualType promotionType) { |
| assert(!mlir::cast<cir::ComplexType>(result.getType()).isIntegerComplex() && |
| "integral complex will never be promoted"); |
| return builder.createCast(cir::CastKind::float_complex, result, |
| convertType(promotionType)); |
| } |
| |
| mlir::Value ComplexExprEmitter::emitPromoted(const Expr *e, |
| QualType promotionTy) { |
| e = e->IgnoreParens(); |
| if (const auto *bo = dyn_cast<BinaryOperator>(e)) { |
| switch (bo->getOpcode()) { |
| #define HANDLE_BINOP(OP) \ |
| case BO_##OP: \ |
| return emitBin##OP(emitBinOps(bo, promotionTy)); |
| HANDLE_BINOP(Add) |
| HANDLE_BINOP(Sub) |
| HANDLE_BINOP(Mul) |
| HANDLE_BINOP(Div) |
| #undef HANDLE_BINOP |
| default: |
| break; |
| } |
| } else if (const auto *unaryOp = dyn_cast<UnaryOperator>(e)) { |
| switch (unaryOp->getOpcode()) { |
| case UO_Minus: |
| case UO_Plus: { |
| auto kind = unaryOp->getOpcode() == UO_Plus ? cir::UnaryOpKind::Plus |
| : cir::UnaryOpKind::Minus; |
| return VisitPlusMinus(unaryOp, kind, promotionTy); |
| } |
| default: |
| break; |
| } |
| } |
| |
| mlir::Value result = Visit(const_cast<Expr *>(e)); |
| if (!promotionTy.isNull()) |
| return cgf.emitPromotedValue(result, promotionTy); |
| |
| return result; |
| } |
| |
| mlir::Value CIRGenFunction::emitPromotedComplexExpr(const Expr *e, |
| QualType promotionType) { |
| return ComplexExprEmitter(*this).emitPromoted(e, promotionType); |
| } |
| |
| mlir::Value |
| ComplexExprEmitter::emitPromotedComplexOperand(const Expr *e, |
| QualType promotionTy) { |
| if (e->getType()->isAnyComplexType()) { |
| if (!promotionTy.isNull()) |
| return cgf.emitPromotedComplexExpr(e, promotionTy); |
| return Visit(const_cast<Expr *>(e)); |
| } |
| |
| if (!promotionTy.isNull()) { |
| QualType complexElementTy = |
| promotionTy->castAs<ComplexType>()->getElementType(); |
| return cgf.emitPromotedScalarExpr(e, complexElementTy); |
| } |
| return cgf.emitScalarExpr(e); |
| } |
| |
| ComplexExprEmitter::BinOpInfo |
| ComplexExprEmitter::emitBinOps(const BinaryOperator *e, QualType promotionTy) { |
| BinOpInfo binOpInfo{cgf.getLoc(e->getExprLoc())}; |
| binOpInfo.lhs = emitPromotedComplexOperand(e->getLHS(), promotionTy); |
| binOpInfo.rhs = emitPromotedComplexOperand(e->getRHS(), promotionTy); |
| binOpInfo.ty = promotionTy.isNull() ? e->getType() : promotionTy; |
| binOpInfo.fpFeatures = e->getFPFeaturesInEffect(cgf.getLangOpts()); |
| return binOpInfo; |
| } |
| |
| LValue ComplexExprEmitter::emitCompoundAssignLValue( |
| const CompoundAssignOperator *e, |
| mlir::Value (ComplexExprEmitter::*func)(const BinOpInfo &), RValue &value) { |
| QualType lhsTy = e->getLHS()->getType(); |
| QualType rhsTy = e->getRHS()->getType(); |
| SourceLocation exprLoc = e->getExprLoc(); |
| mlir::Location loc = cgf.getLoc(exprLoc); |
| |
| if (lhsTy->getAs<AtomicType>()) { |
| cgf.cgm.errorNYI("emitCompoundAssignLValue AtmoicType"); |
| return {}; |
| } |
| |
| BinOpInfo opInfo{loc}; |
| opInfo.fpFeatures = e->getFPFeaturesInEffect(cgf.getLangOpts()); |
| |
| assert(!cir::MissingFeatures::cgFPOptionsRAII()); |
| |
| // Load the RHS and LHS operands. |
| // __block variables need to have the rhs evaluated first, plus this should |
| // improve codegen a little. |
| QualType promotionTypeCR = getPromotionType(e->getComputationResultType()); |
| opInfo.ty = promotionTypeCR.isNull() ? e->getComputationResultType() |
| : promotionTypeCR; |
| |
| QualType complexElementTy = |
| opInfo.ty->castAs<ComplexType>()->getElementType(); |
| QualType promotionTypeRHS = getPromotionType(rhsTy); |
| |
| // The RHS should have been converted to the computation type. |
| if (e->getRHS()->getType()->isRealFloatingType()) { |
| if (!promotionTypeRHS.isNull()) { |
| opInfo.rhs = cgf.emitPromotedScalarExpr(e->getRHS(), promotionTypeRHS); |
| } else { |
| assert(cgf.getContext().hasSameUnqualifiedType(complexElementTy, rhsTy)); |
| opInfo.rhs = cgf.emitScalarExpr(e->getRHS()); |
| } |
| } else { |
| if (!promotionTypeRHS.isNull()) { |
| opInfo.rhs = cgf.emitPromotedComplexExpr(e->getRHS(), promotionTypeRHS); |
| } else { |
| assert(cgf.getContext().hasSameUnqualifiedType(opInfo.ty, rhsTy)); |
| opInfo.rhs = Visit(e->getRHS()); |
| } |
| } |
| |
| LValue lhs = cgf.emitLValue(e->getLHS()); |
| |
| // Load from the l-value and convert it. |
| QualType promotionTypeLHS = getPromotionType(e->getComputationLHSType()); |
| if (lhsTy->isAnyComplexType()) { |
| mlir::Value lhsValue = emitLoadOfLValue(lhs, exprLoc); |
| QualType destTy = promotionTypeLHS.isNull() ? opInfo.ty : promotionTypeLHS; |
| opInfo.lhs = emitComplexToComplexCast(lhsValue, lhsTy, destTy, exprLoc); |
| } else { |
| mlir::Value lhsVal = cgf.emitLoadOfScalar(lhs, exprLoc); |
| // For floating point real operands we can directly pass the scalar form |
| // to the binary operator emission and potentially get more efficient code. |
| if (lhsTy->isRealFloatingType()) { |
| QualType promotedComplexElementTy; |
| if (!promotionTypeLHS.isNull()) { |
| promotedComplexElementTy = |
| cast<ComplexType>(promotionTypeLHS)->getElementType(); |
| if (!cgf.getContext().hasSameUnqualifiedType(promotedComplexElementTy, |
| promotionTypeLHS)) |
| lhsVal = cgf.emitScalarConversion(lhsVal, lhsTy, |
| promotedComplexElementTy, exprLoc); |
| } else { |
| if (!cgf.getContext().hasSameUnqualifiedType(complexElementTy, lhsTy)) |
| lhsVal = cgf.emitScalarConversion(lhsVal, lhsTy, complexElementTy, |
| exprLoc); |
| } |
| opInfo.lhs = lhsVal; |
| } else { |
| opInfo.lhs = emitScalarToComplexCast(lhsVal, lhsTy, opInfo.ty, exprLoc); |
| } |
| } |
| |
| // Expand the binary operator. |
| mlir::Value result = (this->*func)(opInfo); |
| |
| // Truncate the result and store it into the LHS lvalue. |
| if (lhsTy->isAnyComplexType()) { |
| mlir::Value resultValue = |
| emitComplexToComplexCast(result, opInfo.ty, lhsTy, exprLoc); |
| emitStoreOfComplex(loc, resultValue, lhs, /*isInit*/ false); |
| value = RValue::getComplex(resultValue); |
| } else { |
| mlir::Value resultValue = |
| cgf.emitComplexToScalarConversion(result, opInfo.ty, lhsTy, exprLoc); |
| cgf.emitStoreOfScalar(resultValue, lhs, /*isInit*/ false); |
| value = RValue::get(resultValue); |
| } |
| |
| return lhs; |
| } |
| |
| mlir::Value ComplexExprEmitter::emitCompoundAssign( |
| const CompoundAssignOperator *e, |
| mlir::Value (ComplexExprEmitter::*func)(const BinOpInfo &)) { |
| RValue val; |
| LValue lv = emitCompoundAssignLValue(e, func, val); |
| |
| // The result of an assignment in C is the assigned r-value. |
| if (!cgf.getLangOpts().CPlusPlus) |
| return val.getComplexValue(); |
| |
| // If the lvalue is non-volatile, return the computed value of the assignment. |
| if (!lv.isVolatileQualified()) |
| return val.getComplexValue(); |
| |
| return emitLoadOfLValue(lv, e->getExprLoc()); |
| } |
| |
| LValue ComplexExprEmitter::emitBinAssignLValue(const BinaryOperator *e, |
| mlir::Value &value) { |
| assert(cgf.getContext().hasSameUnqualifiedType(e->getLHS()->getType(), |
| e->getRHS()->getType()) && |
| "Invalid assignment"); |
| |
| // Emit the RHS. __block variables need the RHS evaluated first. |
| value = Visit(e->getRHS()); |
| |
| // Compute the address to store into. |
| LValue lhs = cgf.emitLValue(e->getLHS()); |
| |
| // Store the result value into the LHS lvalue. |
| emitStoreOfComplex(cgf.getLoc(e->getExprLoc()), value, lhs, |
| /*isInit*/ false); |
| return lhs; |
| } |
| |
| mlir::Value ComplexExprEmitter::VisitBinAssign(const BinaryOperator *e) { |
| mlir::Value value; |
| LValue lv = emitBinAssignLValue(e, value); |
| |
| // The result of an assignment in C is the assigned r-value. |
| if (!cgf.getLangOpts().CPlusPlus) |
| return value; |
| |
| // If the lvalue is non-volatile, return the computed value of the |
| // assignment. |
| if (!lv.isVolatile()) |
| return value; |
| |
| return emitLoadOfLValue(lv, e->getExprLoc()); |
| } |
| |
| mlir::Value ComplexExprEmitter::VisitBinComma(const BinaryOperator *e) { |
| cgf.emitIgnoredExpr(e->getLHS()); |
| return Visit(e->getRHS()); |
| } |
| |
| mlir::Value ComplexExprEmitter::VisitAbstractConditionalOperator( |
| const AbstractConditionalOperator *e) { |
| mlir::Location loc = cgf.getLoc(e->getSourceRange()); |
| |
| // Bind the common expression if necessary. |
| CIRGenFunction::OpaqueValueMapping binding(cgf, e); |
| |
| CIRGenFunction::ConditionalEvaluation eval(cgf); |
| |
| Expr *cond = e->getCond()->IgnoreParens(); |
| mlir::Value condValue = cgf.evaluateExprAsBool(cond); |
| |
| return builder |
| .create<cir::TernaryOp>( |
| loc, condValue, |
| /*thenBuilder=*/ |
| [&](mlir::OpBuilder &b, mlir::Location loc) { |
| eval.beginEvaluation(); |
| mlir::Value trueValue = Visit(e->getTrueExpr()); |
| b.create<cir::YieldOp>(loc, trueValue); |
| eval.endEvaluation(); |
| }, |
| /*elseBuilder=*/ |
| [&](mlir::OpBuilder &b, mlir::Location loc) { |
| eval.beginEvaluation(); |
| mlir::Value falseValue = Visit(e->getFalseExpr()); |
| b.create<cir::YieldOp>(loc, falseValue); |
| eval.endEvaluation(); |
| }) |
| .getResult(); |
| } |
| |
| mlir::Value ComplexExprEmitter::VisitChooseExpr(ChooseExpr *e) { |
| return Visit(e->getChosenSubExpr()); |
| } |
| |
| mlir::Value ComplexExprEmitter::VisitInitListExpr(InitListExpr *e) { |
| mlir::Location loc = cgf.getLoc(e->getExprLoc()); |
| if (e->getNumInits() == 2) { |
| mlir::Value real = cgf.emitScalarExpr(e->getInit(0)); |
| mlir::Value imag = cgf.emitScalarExpr(e->getInit(1)); |
| return builder.createComplexCreate(loc, real, imag); |
| } |
| |
| if (e->getNumInits() == 1) |
| return Visit(e->getInit(0)); |
| |
| assert(e->getNumInits() == 0 && "Unexpected number of inits"); |
| mlir::Type complexTy = cgf.convertType(e->getType()); |
| return builder.getNullValue(complexTy, loc); |
| } |
| |
| mlir::Value ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *e) { |
| return cgf.emitVAArg(e); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Entry Point into this File |
| //===----------------------------------------------------------------------===// |
| |
| /// EmitComplexExpr - Emit the computation of the specified expression of |
| /// complex type, ignoring the result. |
| mlir::Value CIRGenFunction::emitComplexExpr(const Expr *e) { |
| assert(e && getComplexType(e->getType()) && |
| "Invalid complex expression to emit"); |
| |
| return ComplexExprEmitter(*this).Visit(const_cast<Expr *>(e)); |
| } |
| |
| void CIRGenFunction::emitComplexExprIntoLValue(const Expr *e, LValue dest, |
| bool isInit) { |
| assert(e && getComplexType(e->getType()) && |
| "Invalid complex expression to emit"); |
| ComplexExprEmitter emitter(*this); |
| mlir::Value value = emitter.Visit(const_cast<Expr *>(e)); |
| emitter.emitStoreOfComplex(getLoc(e->getExprLoc()), value, dest, isInit); |
| } |
| |
| /// EmitStoreOfComplex - Store a complex number into the specified l-value. |
| void CIRGenFunction::emitStoreOfComplex(mlir::Location loc, mlir::Value v, |
| LValue dest, bool isInit) { |
| ComplexExprEmitter(*this).emitStoreOfComplex(loc, v, dest, isInit); |
| } |
| |
| mlir::Value CIRGenFunction::emitLoadOfComplex(LValue src, SourceLocation loc) { |
| return ComplexExprEmitter(*this).emitLoadOfLValue(src, loc); |
| } |
| |
| LValue CIRGenFunction::emitComplexAssignmentLValue(const BinaryOperator *e) { |
| assert(e->getOpcode() == BO_Assign && "Expected assign op"); |
| |
| mlir::Value value; // ignored |
| LValue lvalue = ComplexExprEmitter(*this).emitBinAssignLValue(e, value); |
| if (getLangOpts().OpenMP) |
| cgm.errorNYI("emitComplexAssignmentLValue OpenMP"); |
| |
| return lvalue; |
| } |
| |
| using CompoundFunc = |
| mlir::Value (ComplexExprEmitter::*)(const ComplexExprEmitter::BinOpInfo &); |
| |
| static CompoundFunc getComplexOp(BinaryOperatorKind op) { |
| switch (op) { |
| case BO_MulAssign: |
| return &ComplexExprEmitter::emitBinMul; |
| case BO_DivAssign: |
| return &ComplexExprEmitter::emitBinDiv; |
| case BO_SubAssign: |
| return &ComplexExprEmitter::emitBinSub; |
| case BO_AddAssign: |
| return &ComplexExprEmitter::emitBinAdd; |
| default: |
| llvm_unreachable("unexpected complex compound assignment"); |
| } |
| } |
| |
| LValue CIRGenFunction::emitComplexCompoundAssignmentLValue( |
| const CompoundAssignOperator *e) { |
| CompoundFunc op = getComplexOp(e->getOpcode()); |
| RValue val; |
| return ComplexExprEmitter(*this).emitCompoundAssignLValue(e, op, val); |
| } |
| |
| mlir::Value CIRGenFunction::emitComplexPrePostIncDec(const UnaryOperator *e, |
| LValue lv, |
| cir::UnaryOpKind op, |
| bool isPre) { |
| assert(op == cir::UnaryOpKind::Inc || |
| op == cir::UnaryOpKind::Dec && "Invalid UnaryOp kind for ComplexType"); |
| |
| mlir::Value inVal = emitLoadOfComplex(lv, e->getExprLoc()); |
| mlir::Location loc = getLoc(e->getExprLoc()); |
| mlir::Value incVal = builder.createUnaryOp(loc, op, inVal); |
| |
| // Store the updated result through the lvalue. |
| emitStoreOfComplex(loc, incVal, lv, /*isInit=*/false); |
| |
| if (getLangOpts().OpenMP) |
| cgm.errorNYI(loc, "emitComplexPrePostIncDec OpenMP"); |
| |
| // If this is a postinc, return the value read from memory, otherwise use the |
| // updated value. |
| return isPre ? incVal : inVal; |
| } |
| |
| LValue CIRGenFunction::emitScalarCompoundAssignWithComplex( |
| const CompoundAssignOperator *e, mlir::Value &result) { |
| // Key Instructions: Don't need to create an atom group here; one will already |
| // be active through scalar handling code. |
| CompoundFunc op = getComplexOp(e->getOpcode()); |
| RValue value; |
| LValue ret = ComplexExprEmitter(*this).emitCompoundAssignLValue(e, op, value); |
| result = value.getValue(); |
| return ret; |
| } |