blob: f84f6157a61f7d10af24e0d500561792e9833e48 [file] [log] [blame]
#include "CIRGenBuilder.h"
#include "CIRGenCstEmitter.h"
#include "CIRGenFunction.h"
#include "clang/Basic/LangOptions.h"
#include "clang/CIR/Interfaces/CIRFPTypeInterface.h"
#include "clang/CIR/MissingFeatures.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/Value.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/Support/ErrorHandling.h"
using namespace cir;
using namespace clang;
namespace {
class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
CIRGenFunction &CGF;
CIRGenBuilderTy &Builder;
bool FPHasBeenPromoted;
public:
explicit ComplexExprEmitter(CIRGenFunction &cgf)
: CGF(cgf), Builder(cgf.getBuilder()), FPHasBeenPromoted(false) {}
//===--------------------------------------------------------------------===//
// 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 buildLoadOfLValue(const Expr *E) {
return buildLoadOfLValue(CGF.buildLValue(E), E->getExprLoc());
}
mlir::Value buildLoadOfLValue(LValue LV, SourceLocation Loc);
/// EmitStoreOfComplex - Store the specified real/imag parts into the
/// specified value pointer.
void buildStoreOfComplex(mlir::Location Loc, mlir::Value Val, LValue LV,
bool isInit);
/// Emit a cast from complex value Val to DestType.
mlir::Value buildComplexToComplexCast(mlir::Value Val, QualType SrcType,
QualType DestType, SourceLocation Loc);
/// Emit a cast from scalar value Val to DestType.
mlir::Value buildScalarToComplexCast(mlir::Value Val, QualType SrcType,
QualType DestType, SourceLocation Loc);
//===--------------------------------------------------------------------===//
// Visitor Methods
//===--------------------------------------------------------------------===//
mlir::Value Visit(Expr *E) {
assert(!MissingFeatures::generateDebugInfo());
return StmtVisitor<ComplexExprEmitter, mlir::Value>::Visit(E);
}
mlir::Value VisitStmt(Stmt *S) {
S->dump(llvm::errs(), CGF.getContext());
llvm_unreachable("Stmt can't have complex result type!");
}
mlir::Value VisitExpr(Expr *S) { llvm_unreachable("not supported"); }
mlir::Value VisitConstantExpr(ConstantExpr *E) {
if (auto Result = ConstantEmitter(CGF).tryEmitConstantExpr(E))
return Builder.getConstant(CGF.getLoc(E->getSourceRange()),
mlir::cast<mlir::TypedAttr>(Result));
return Visit(E->getSubExpr());
}
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) { llvm_unreachable("NYI"); }
mlir::Value VisitCoyieldExpr(CoyieldExpr *S) { llvm_unreachable("NYI"); }
mlir::Value VisitUnaryCoawait(const UnaryOperator *E) {
return Visit(E->getSubExpr());
}
mlir::Value emitConstant(const CIRGenFunction::ConstantEmission &Constant,
Expr *E) {
assert(Constant && "not a constant");
if (Constant.isReference())
return buildLoadOfLValue(Constant.getReferenceLValue(CGF, E),
E->getExprLoc());
auto 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 buildLoadOfLValue(E);
}
mlir::Value VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
llvm_unreachable("NYI");
}
mlir::Value VisitObjCMessageExpr(ObjCMessageExpr *E) {
llvm_unreachable("NYI");
}
mlir::Value VisitArraySubscriptExpr(Expr *E) { llvm_unreachable("NYI"); }
mlir::Value VisitMemberExpr(MemberExpr *ME) { llvm_unreachable("NYI"); }
mlir::Value VisitOpaqueValueExpr(OpaqueValueExpr *E) {
llvm_unreachable("NYI");
}
mlir::Value VisitPseudoObjectExpr(PseudoObjectExpr *E) {
llvm_unreachable("NYI");
}
// FIXME: CompoundLiteralExpr
mlir::Value buildCast(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 buildLoadOfLValue(E);
return buildCast(E->getCastKind(), E->getSubExpr(), E->getType());
}
mlir::Value VisitCastExpr(CastExpr *E);
mlir::Value VisitCallExpr(const CallExpr *E);
mlir::Value VisitStmtExpr(const StmtExpr *E) { llvm_unreachable("NYI"); }
// Operators.
mlir::Value VisitPrePostIncDec(const UnaryOperator *E, bool isInc,
bool isPre);
mlir::Value VisitUnaryPostDec(const UnaryOperator *E) {
return VisitPrePostIncDec(E, false, false);
}
mlir::Value VisitUnaryPostInc(const UnaryOperator *E) {
return VisitPrePostIncDec(E, true, false);
}
mlir::Value VisitUnaryPreDec(const UnaryOperator *E) {
return VisitPrePostIncDec(E, false, true);
}
mlir::Value VisitUnaryPreInc(const UnaryOperator *E) {
return VisitPrePostIncDec(E, true, true);
}
mlir::Value VisitUnaryDeref(const Expr *E) { llvm_unreachable("NYI"); }
mlir::Value VisitUnaryPlus(const UnaryOperator *E,
QualType PromotionType = QualType());
mlir::Value VisitPlus(const UnaryOperator *E, QualType PromotionType);
mlir::Value VisitUnaryMinus(const UnaryOperator *E,
QualType PromotionType = QualType());
mlir::Value VisitMinus(const UnaryOperator *E, QualType PromotionType);
mlir::Value VisitUnaryNot(const UnaryOperator *E);
// LNot,Real,Imag never return complex.
mlir::Value VisitUnaryExtension(const UnaryOperator *E) {
return Visit(E->getSubExpr());
}
mlir::Value VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
llvm_unreachable("NYI");
}
mlir::Value VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
llvm_unreachable("NYI");
}
mlir::Value VisitExprWithCleanups(ExprWithCleanups *E) {
CIRGenFunction::RunCleanupsScope Scope(CGF);
mlir::Value V = Visit(E->getSubExpr());
// Defend against dominance problems caused by jumps out of expression
// evaluation through the shared cleanup block.
Scope.ForceCleanup({&V});
return V;
}
mlir::Value VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
llvm_unreachable("NYI");
}
mlir::Value VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
llvm_unreachable("NYI");
}
struct BinOpInfo {
mlir::Location Loc;
mlir::Value LHS{};
mlir::Value RHS{};
QualType Ty{}; // Computation Type.
FPOptions FPFeatures{};
};
BinOpInfo buildBinOps(const BinaryOperator *E,
QualType PromotionTy = QualType());
mlir::Value buildPromoted(const Expr *E, QualType PromotionTy);
mlir::Value buildPromotedComplexOperand(const Expr *E, QualType PromotionTy);
LValue buildCompoundAssignLValue(
const CompoundAssignOperator *E,
mlir::Value (ComplexExprEmitter::*Func)(const BinOpInfo &), RValue &Val);
mlir::Value buildCompoundAssign(
const CompoundAssignOperator *E,
mlir::Value (ComplexExprEmitter::*Func)(const BinOpInfo &));
mlir::Value buildBinAdd(const BinOpInfo &Op);
mlir::Value buildBinSub(const BinOpInfo &Op);
mlir::Value buildBinMul(const BinOpInfo &Op);
mlir::Value buildBinDiv(const BinOpInfo &Op);
QualType GetHigherPrecisionFPType(QualType ElementType) {
const auto *CurrentBT = cast<BuiltinType>(ElementType);
switch (CurrentBT->getKind()) {
case BuiltinType::Kind::Float16:
return CGF.getContext().FloatTy;
case BuiltinType::Kind::Float:
case BuiltinType::Kind::BFloat16:
return CGF.getContext().DoubleTy;
case BuiltinType::Kind::Double:
return CGF.getContext().LongDoubleTy;
default:
return ElementType;
}
}
QualType HigherPrecisionTypeForComplexArithmetic(QualType ElementType,
bool IsDivOpCode) {
QualType HigherElementType = GetHigherPrecisionFPType(ElementType);
const llvm::fltSemantics &ElementTypeSemantics =
CGF.getContext().getFloatTypeSemantics(ElementType);
const llvm::fltSemantics &HigherElementTypeSemantics =
CGF.getContext().getFloatTypeSemantics(HigherElementType);
// Check that the promoted type can handle the intermediate values without
// overflowing. This can be interpreted as:
// (SmallerType.LargestFiniteVal * SmallerType.LargestFiniteVal) * 2 <=
// LargerType.LargestFiniteVal.
// In terms of exponent it gives this formula:
// (SmallerType.LargestFiniteVal * SmallerType.LargestFiniteVal
// doubles the exponent of SmallerType.LargestFiniteVal)
if (llvm::APFloat::semanticsMaxExponent(ElementTypeSemantics) * 2 + 1 <=
llvm::APFloat::semanticsMaxExponent(HigherElementTypeSemantics)) {
FPHasBeenPromoted = true;
return CGF.getContext().getComplexType(HigherElementType);
}
DiagnosticsEngine &Diags = CGF.CGM.getDiags();
Diags.Report(diag::warn_next_larger_fp_type_same_size_than_fp);
return QualType();
}
QualType getPromotionType(QualType Ty, bool IsDivOpCode = false) {
if (auto *CT = Ty->getAs<ComplexType>()) {
QualType ElementType = CT->getElementType();
if (IsDivOpCode && ElementType->isFloatingType() &&
CGF.getLangOpts().getComplexRange() ==
LangOptions::ComplexRangeKind::CX_Promoted)
return HigherPrecisionTypeForComplexArithmetic(ElementType,
IsDivOpCode);
if (ElementType.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) ? true : false); \
mlir::Value result = buildBin##OP(buildBinOps(E, promotionTy)); \
if (!promotionTy.isNull()) \
result = CGF.buildUnPromotedValue(result, E->getType()); \
return result; \
}
HANDLEBINOP(Mul)
HANDLEBINOP(Div)
HANDLEBINOP(Add)
HANDLEBINOP(Sub)
#undef HANDLEBINOP
mlir::Value VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *E) {
llvm_unreachable("NYI");
}
// Compound assignments.
mlir::Value VisitBinAddAssign(const CompoundAssignOperator *E) {
return buildCompoundAssign(E, &ComplexExprEmitter::buildBinAdd);
}
mlir::Value VisitBinSubAssign(const CompoundAssignOperator *E) {
return buildCompoundAssign(E, &ComplexExprEmitter::buildBinSub);
}
mlir::Value VisitBinMulAssign(const CompoundAssignOperator *E) {
return buildCompoundAssign(E, &ComplexExprEmitter::buildBinMul);
}
mlir::Value VisitBinDivAssign(const CompoundAssignOperator *E) {
return buildCompoundAssign(E, &ComplexExprEmitter::buildBinDiv);
}
// GCC rejects rem/and/or/xor for integer complex.
// Logical and/or always return int, never complex.
// No comparisons produce a complex result.
LValue buildBinAssignLValue(const BinaryOperator *E, mlir::Value &Val);
mlir::Value VisitBinAssign(const BinaryOperator *E) {
mlir::Value Val;
LValue LV = buildBinAssignLValue(E, Val);
// The result of an assignment in C is the assigned r-value.
if (!CGF.getLangOpts().CPlusPlus)
return Val;
// If the lvalue is non-volatile, return the computed value of the
// assignment.
if (!LV.isVolatileQualified())
return Val;
return buildLoadOfLValue(LV, E->getExprLoc());
};
mlir::Value VisitBinComma(const BinaryOperator *E) {
llvm_unreachable("NYI");
}
mlir::Value
VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO) {
llvm_unreachable("NYI");
}
mlir::Value VisitChooseExpr(ChooseExpr *CE) { llvm_unreachable("NYI"); }
mlir::Value VisitInitListExpr(InitListExpr *E);
mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
llvm_unreachable("NYI");
}
mlir::Value VisitVAArgExpr(VAArgExpr *E) { llvm_unreachable("NYI"); }
mlir::Value VisitAtomicExpr(AtomicExpr *E) { llvm_unreachable("NYI"); }
mlir::Value VisitPackIndexingExpr(PackIndexingExpr *E) {
llvm_unreachable("NYI");
}
};
} // namespace
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());
}
static mlir::Value createComplexFromReal(CIRGenBuilderTy &builder,
mlir::Location loc, mlir::Value real) {
mlir::Value imag = builder.getNullValue(real.getType(), loc);
return builder.createComplexCreate(loc, real, imag);
}
mlir::Value ComplexExprEmitter::buildLoadOfLValue(LValue LV,
SourceLocation Loc) {
assert(LV.isSimple() && "non-simple complex l-value?");
if (LV.getType()->isAtomicType())
llvm_unreachable("NYI");
Address SrcPtr = LV.getAddress();
return Builder.createLoad(CGF.getLoc(Loc), SrcPtr, LV.isVolatileQualified());
}
void ComplexExprEmitter::buildStoreOfComplex(mlir::Location Loc,
mlir::Value Val, LValue LV,
bool isInit) {
if (LV.getType()->isAtomicType() ||
(!isInit && CGF.LValueIsSuitableForInlineAtomic(LV)))
llvm_unreachable("NYI");
Address DestAddr = LV.getAddress();
Builder.createStore(Loc, Val, DestAddr, LV.isVolatileQualified());
}
mlir::Value ComplexExprEmitter::buildComplexToComplexCast(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();
mlir::cir::CastKind CastOpKind;
if (SrcElemTy->isFloatingType() && DestElemTy->isFloatingType())
CastOpKind = mlir::cir::CastKind::float_complex;
else if (SrcElemTy->isFloatingType() && DestElemTy->isIntegerType())
CastOpKind = mlir::cir::CastKind::float_complex_to_int_complex;
else if (SrcElemTy->isIntegerType() && DestElemTy->isFloatingType())
CastOpKind = mlir::cir::CastKind::int_complex_to_float_complex;
else if (SrcElemTy->isIntegerType() && DestElemTy->isIntegerType())
CastOpKind = mlir::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::buildScalarToComplexCast(mlir::Value Val,
QualType SrcType,
QualType DestType,
SourceLocation Loc) {
mlir::cir::CastKind CastOpKind;
if (SrcType->isFloatingType())
CastOpKind = mlir::cir::CastKind::float_to_complex;
else if (SrcType->isIntegerType())
CastOpKind = mlir::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::buildCast(CastKind CK, Expr *Op,
QualType DestTy) {
switch (CK) {
case CK_Dependent:
llvm_unreachable("dependent cast kind in IR gen!");
// Atomic to non-atomic casts may be more than a no-op for some platforms and
// for some types.
case CK_LValueToRValue:
return Visit(Op);
case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
case CK_NoOp:
case CK_UserDefinedConversion:
llvm_unreachable("NYI");
case CK_LValueBitCast:
llvm_unreachable("NYI");
case CK_LValueToRValueBitCast:
llvm_unreachable("NYI");
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:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
case CK_IntegralRealToComplex: {
assert(!MissingFeatures::CGFPOptionsRAII());
return buildScalarToComplexCast(CGF.buildScalarExpr(Op), Op->getType(),
DestTy, Op->getExprLoc());
}
case CK_FloatingComplexCast:
case CK_FloatingComplexToIntegralComplex:
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex: {
assert(!MissingFeatures::CGFPOptionsRAII());
return buildComplexToComplexCast(Visit(Op), Op->getType(), DestTy,
Op->getExprLoc());
}
}
llvm_unreachable("unknown cast resulting in complex value");
}
mlir::Value ComplexExprEmitter::VisitCastExpr(CastExpr *E) {
if (const auto *ECE = dyn_cast<ExplicitCastExpr>(E))
CGF.CGM.buildExplicitCastExprType(ECE, &CGF);
if (E->changesVolatileQualification())
return buildLoadOfLValue(E);
return buildCast(E->getCastKind(), E->getSubExpr(), E->getType());
}
mlir::Value ComplexExprEmitter::VisitCallExpr(const CallExpr *E) {
if (E->getCallReturnType(CGF.getContext())->isReferenceType())
return buildLoadOfLValue(E);
return CGF.buildCallExpr(E).getComplexVal();
}
mlir::Value ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
bool isInc, bool isPre) {
LValue LV = CGF.buildLValue(E->getSubExpr());
return CGF.buildComplexPrePostIncDec(E, LV, isInc, isPre);
}
mlir::Value ComplexExprEmitter::VisitUnaryPlus(const UnaryOperator *E,
QualType PromotionType) {
QualType promotionTy = PromotionType.isNull()
? getPromotionType(E->getSubExpr()->getType())
: PromotionType;
mlir::Value result = VisitPlus(E, promotionTy);
if (!promotionTy.isNull())
return CGF.buildUnPromotedValue(result, E->getSubExpr()->getType());
return result;
}
mlir::Value ComplexExprEmitter::VisitPlus(const UnaryOperator *E,
QualType PromotionType) {
mlir::Value Op;
if (!PromotionType.isNull())
Op = CGF.buildPromotedComplexExpr(E->getSubExpr(), PromotionType);
else
Op = Visit(E->getSubExpr());
return Builder.createUnaryOp(CGF.getLoc(E->getExprLoc()),
mlir::cir::UnaryOpKind::Plus, Op);
}
mlir::Value ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E,
QualType PromotionType) {
QualType promotionTy = PromotionType.isNull()
? getPromotionType(E->getSubExpr()->getType())
: PromotionType;
mlir::Value result = VisitMinus(E, promotionTy);
if (!promotionTy.isNull())
return CGF.buildUnPromotedValue(result, E->getSubExpr()->getType());
return result;
}
mlir::Value ComplexExprEmitter::VisitMinus(const UnaryOperator *E,
QualType PromotionType) {
mlir::Value Op;
if (!PromotionType.isNull())
Op = CGF.buildPromotedComplexExpr(E->getSubExpr(), PromotionType);
else
Op = Visit(E->getSubExpr());
return Builder.createUnaryOp(CGF.getLoc(E->getExprLoc()),
mlir::cir::UnaryOpKind::Minus, Op);
}
mlir::Value ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
mlir::Value Op = Visit(E->getSubExpr());
return Builder.createUnaryOp(CGF.getLoc(E->getExprLoc()),
mlir::cir::UnaryOpKind::Not, Op);
}
ComplexExprEmitter::BinOpInfo
ComplexExprEmitter::buildBinOps(const BinaryOperator *E, QualType PromotionTy) {
BinOpInfo Ops{CGF.getLoc(E->getExprLoc())};
Ops.LHS = buildPromotedComplexOperand(E->getLHS(), PromotionTy);
Ops.RHS = buildPromotedComplexOperand(E->getRHS(), PromotionTy);
if (!PromotionTy.isNull())
Ops.Ty = PromotionTy;
else
Ops.Ty = E->getType();
Ops.FPFeatures = E->getFPFeaturesInEffect(CGF.getLangOpts());
return Ops;
}
mlir::Value ComplexExprEmitter::buildPromoted(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 buildBin##OP(buildBinOps(BO, PromotionTy));
HANDLE_BINOP(Add)
HANDLE_BINOP(Sub)
HANDLE_BINOP(Mul)
HANDLE_BINOP(Div)
#undef HANDLE_BINOP
default:
break;
}
} else if (const auto *UO = dyn_cast<UnaryOperator>(E)) {
switch (UO->getOpcode()) {
case UO_Minus:
return VisitMinus(UO, PromotionTy);
case UO_Plus:
return VisitPlus(UO, PromotionTy);
default:
break;
}
}
auto result = Visit(const_cast<Expr *>(E));
if (!PromotionTy.isNull())
return CGF.buildPromotedValue(result, PromotionTy);
return result;
}
mlir::Value
ComplexExprEmitter::buildPromotedComplexOperand(const Expr *E,
QualType PromotionTy) {
if (E->getType()->isAnyComplexType()) {
if (!PromotionTy.isNull())
return CGF.buildPromotedComplexExpr(E, PromotionTy);
return Visit(const_cast<Expr *>(E));
}
mlir::Value Real;
if (!PromotionTy.isNull()) {
QualType ComplexElementTy =
PromotionTy->castAs<ComplexType>()->getElementType();
Real = CGF.buildPromotedScalarExpr(E, ComplexElementTy);
} else
Real = CGF.buildScalarExpr(E);
return createComplexFromReal(CGF.getBuilder(), CGF.getLoc(E->getExprLoc()),
Real);
}
LValue ComplexExprEmitter::buildCompoundAssignLValue(
const CompoundAssignOperator *E,
mlir::Value (ComplexExprEmitter::*Func)(const BinOpInfo &), RValue &Val) {
QualType LHSTy = E->getLHS()->getType();
if (const AtomicType *AT = LHSTy->getAs<AtomicType>())
LHSTy = AT->getValueType();
BinOpInfo OpInfo{CGF.getLoc(E->getExprLoc())};
OpInfo.FPFeatures = E->getFPFeaturesInEffect(CGF.getLangOpts());
assert(!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;
PromotionTypeCR = getPromotionType(E->getComputationResultType());
if (PromotionTypeCR.isNull())
PromotionTypeCR = E->getComputationResultType();
OpInfo.Ty = PromotionTypeCR;
QualType ComplexElementTy =
OpInfo.Ty->castAs<ComplexType>()->getElementType();
QualType PromotionTypeRHS = getPromotionType(E->getRHS()->getType());
// The RHS should have been converted to the computation type.
if (E->getRHS()->getType()->isRealFloatingType()) {
if (!PromotionTypeRHS.isNull())
OpInfo.RHS = createComplexFromReal(
CGF.getBuilder(), CGF.getLoc(E->getExprLoc()),
CGF.buildPromotedScalarExpr(E->getRHS(), PromotionTypeRHS));
else {
assert(CGF.getContext().hasSameUnqualifiedType(ComplexElementTy,
E->getRHS()->getType()));
OpInfo.RHS =
createComplexFromReal(CGF.getBuilder(), CGF.getLoc(E->getExprLoc()),
CGF.buildScalarExpr(E->getRHS()));
}
} else {
if (!PromotionTypeRHS.isNull()) {
OpInfo.RHS = createComplexFromReal(
CGF.getBuilder(), CGF.getLoc(E->getExprLoc()),
CGF.buildPromotedComplexExpr(E->getRHS(), PromotionTypeRHS));
} else {
assert(CGF.getContext().hasSameUnqualifiedType(OpInfo.Ty,
E->getRHS()->getType()));
OpInfo.RHS = Visit(E->getRHS());
}
}
LValue LHS = CGF.buildLValue(E->getLHS());
// Load from the l-value and convert it.
SourceLocation Loc = E->getExprLoc();
QualType PromotionTypeLHS = getPromotionType(E->getComputationLHSType());
if (LHSTy->isAnyComplexType()) {
mlir::Value LHSVal = buildLoadOfLValue(LHS, Loc);
if (!PromotionTypeLHS.isNull())
OpInfo.LHS =
buildComplexToComplexCast(LHSVal, LHSTy, PromotionTypeLHS, Loc);
else
OpInfo.LHS = buildComplexToComplexCast(LHSVal, LHSTy, OpInfo.Ty, Loc);
} else {
mlir::Value LHSVal = CGF.buildLoadOfScalar(LHS, Loc);
// 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.buildScalarConversion(LHSVal, LHSTy,
PromotedComplexElementTy, Loc);
} else {
if (!CGF.getContext().hasSameUnqualifiedType(ComplexElementTy, LHSTy))
LHSVal =
CGF.buildScalarConversion(LHSVal, LHSTy, ComplexElementTy, Loc);
}
OpInfo.LHS = createComplexFromReal(CGF.getBuilder(),
CGF.getLoc(E->getExprLoc()), LHSVal);
} else {
OpInfo.LHS = buildScalarToComplexCast(LHSVal, LHSTy, OpInfo.Ty, Loc);
}
}
// 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 ResVal =
buildComplexToComplexCast(Result, OpInfo.Ty, LHSTy, Loc);
buildStoreOfComplex(CGF.getLoc(E->getExprLoc()), ResVal, LHS,
/*isInit*/ false);
Val = RValue::getComplex(ResVal);
} else {
mlir::Value ResVal =
CGF.buildComplexToScalarConversion(Result, OpInfo.Ty, LHSTy, Loc);
CGF.buildStoreOfScalar(ResVal, LHS, /*isInit*/ false);
Val = RValue::get(ResVal);
}
return LHS;
}
mlir::Value ComplexExprEmitter::buildCompoundAssign(
const CompoundAssignOperator *E,
mlir::Value (ComplexExprEmitter::*Func)(const BinOpInfo &)) {
RValue Val;
LValue LV = buildCompoundAssignLValue(E, Func, Val);
// The result of an assignment in C is the assigned r-value.
if (!CGF.getLangOpts().CPlusPlus)
return Val.getComplexVal();
// If the lvalue is non-volatile, return the computed value of the assignment.
if (!LV.isVolatileQualified())
return Val.getComplexVal();
return buildLoadOfLValue(LV, E->getExprLoc());
}
mlir::Value ComplexExprEmitter::buildBinAdd(const BinOpInfo &Op) {
assert(!MissingFeatures::CGFPOptionsRAII());
return CGF.getBuilder().createComplexAdd(Op.Loc, Op.LHS, Op.RHS);
}
mlir::Value ComplexExprEmitter::buildBinSub(const BinOpInfo &Op) {
assert(!MissingFeatures::CGFPOptionsRAII());
return CGF.getBuilder().createComplexSub(Op.Loc, Op.LHS, Op.RHS);
}
static mlir::cir::ComplexRangeKind
getComplexRangeAttr(LangOptions::ComplexRangeKind range) {
switch (range) {
case LangOptions::CX_Full:
return mlir::cir::ComplexRangeKind::Full;
case LangOptions::CX_Improved:
return mlir::cir::ComplexRangeKind::Improved;
case LangOptions::CX_Promoted:
return mlir::cir::ComplexRangeKind::Promoted;
case LangOptions::CX_Basic:
return mlir::cir::ComplexRangeKind::Basic;
case LangOptions::CX_None:
return mlir::cir::ComplexRangeKind::None;
}
}
mlir::Value ComplexExprEmitter::buildBinMul(const BinOpInfo &Op) {
assert(!MissingFeatures::CGFPOptionsRAII());
return CGF.getBuilder().createComplexMul(
Op.Loc, Op.LHS, Op.RHS,
getComplexRangeAttr(Op.FPFeatures.getComplexRange()), FPHasBeenPromoted);
}
mlir::Value ComplexExprEmitter::buildBinDiv(const BinOpInfo &Op) {
assert(!MissingFeatures::CGFPOptionsRAII());
return CGF.getBuilder().createComplexDiv(
Op.Loc, Op.LHS, Op.RHS,
getComplexRangeAttr(Op.FPFeatures.getComplexRange()), FPHasBeenPromoted);
}
LValue ComplexExprEmitter::buildBinAssignLValue(const BinaryOperator *E,
mlir::Value &Val) {
assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
E->getRHS()->getType()) &&
"Invalid assignment");
// Emit the RHS. __block variables need the RHS evaluated first.
Val = Visit(E->getRHS());
// Compute the address to store into.
LValue LHS = CGF.buildLValue(E->getLHS());
// Store the result value into the LHS lvalue.
buildStoreOfComplex(CGF.getLoc(E->getExprLoc()), Val, LHS, /*isInit*/ false);
return LHS;
}
mlir::Value
ComplexExprEmitter::VisitImaginaryLiteral(const ImaginaryLiteral *IL) {
auto Loc = CGF.getLoc(IL->getExprLoc());
auto Ty = mlir::cast<mlir::cir::ComplexType>(CGF.getCIRType(IL->getType()));
auto ElementTy = Ty.getElementTy();
mlir::TypedAttr RealValueAttr;
mlir::TypedAttr ImagValueAttr;
if (mlir::isa<mlir::cir::IntType>(ElementTy)) {
auto ImagValue = cast<IntegerLiteral>(IL->getSubExpr())->getValue();
RealValueAttr = mlir::cir::IntAttr::get(ElementTy, 0);
ImagValueAttr = mlir::cir::IntAttr::get(ElementTy, ImagValue);
} else if (mlir::isa<mlir::cir::CIRFPTypeInterface>(ElementTy)) {
auto ImagValue = cast<FloatingLiteral>(IL->getSubExpr())->getValue();
RealValueAttr = mlir::cir::FPAttr::get(
ElementTy, llvm::APFloat::getZero(ImagValue.getSemantics()));
ImagValueAttr = mlir::cir::FPAttr::get(ElementTy, ImagValue);
} else
llvm_unreachable("unexpected complex element type");
auto RealValue = Builder.getConstant(Loc, RealValueAttr);
auto ImagValue = Builder.getConstant(Loc, ImagValueAttr);
return Builder.createComplexCreate(Loc, RealValue, ImagValue);
}
mlir::Value ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (E->getNumInits() == 2) {
mlir::Value Real = CGF.buildScalarExpr(E->getInit(0));
mlir::Value Imag = CGF.buildScalarExpr(E->getInit(1));
return Builder.createComplexCreate(CGF.getLoc(E->getExprLoc()), Real, Imag);
}
if (E->getNumInits() == 1)
return Visit(E->getInit(0));
// Empty init list initializes to null
assert(E->getNumInits() == 0 && "Unexpected number of inits");
QualType Ty = E->getType()->castAs<ComplexType>()->getElementType();
return Builder.getZero(CGF.getLoc(E->getExprLoc()), CGF.ConvertType(Ty));
}
mlir::Value CIRGenFunction::buildPromotedComplexExpr(const Expr *E,
QualType PromotionType) {
return ComplexExprEmitter(*this).buildPromoted(E, PromotionType);
}
mlir::Value CIRGenFunction::buildPromotedValue(mlir::Value result,
QualType PromotionType) {
assert(mlir::isa<mlir::cir::CIRFPTypeInterface>(
mlir::cast<mlir::cir::ComplexType>(result.getType())
.getElementTy()) &&
"integral complex will never be promoted");
return builder.createCast(mlir::cir::CastKind::float_complex, result,
ConvertType(PromotionType));
}
mlir::Value CIRGenFunction::buildUnPromotedValue(mlir::Value result,
QualType UnPromotionType) {
assert(mlir::isa<mlir::cir::CIRFPTypeInterface>(
mlir::cast<mlir::cir::ComplexType>(result.getType())
.getElementTy()) &&
"integral complex will never be promoted");
return builder.createCast(mlir::cir::CastKind::float_complex, result,
ConvertType(UnPromotionType));
}
mlir::Value CIRGenFunction::buildComplexExpr(const Expr *E) {
assert(E && getComplexType(E->getType()) &&
"Invalid complex expression to emit");
return ComplexExprEmitter(*this).Visit(const_cast<Expr *>(E));
}
void CIRGenFunction::buildComplexExprIntoLValue(const Expr *E, LValue dest,
bool isInit) {
assert(E && getComplexType(E->getType()) &&
"Invalid complex expression to emit");
ComplexExprEmitter Emitter(*this);
mlir::Value Val = Emitter.Visit(const_cast<Expr *>(E));
Emitter.buildStoreOfComplex(getLoc(E->getExprLoc()), Val, dest, isInit);
}
void CIRGenFunction::buildStoreOfComplex(mlir::Location Loc, mlir::Value V,
LValue dest, bool isInit) {
ComplexExprEmitter(*this).buildStoreOfComplex(Loc, V, dest, isInit);
}
Address CIRGenFunction::buildAddrOfRealComponent(mlir::Location loc,
Address addr,
QualType complexType) {
return builder.createRealPtr(loc, addr);
}
Address CIRGenFunction::buildAddrOfImagComponent(mlir::Location loc,
Address addr,
QualType complexType) {
return builder.createImagPtr(loc, addr);
}
LValue CIRGenFunction::buildComplexAssignmentLValue(const BinaryOperator *E) {
assert(E->getOpcode() == BO_Assign);
mlir::Value Val; // ignored
LValue LVal = ComplexExprEmitter(*this).buildBinAssignLValue(E, Val);
if (getLangOpts().OpenMP)
llvm_unreachable("NYI");
return LVal;
}
using CompoundFunc =
mlir::Value (ComplexExprEmitter::*)(const ComplexExprEmitter::BinOpInfo &);
static CompoundFunc getComplexOp(BinaryOperatorKind Op) {
switch (Op) {
case BO_MulAssign:
return &ComplexExprEmitter::buildBinMul;
case BO_DivAssign:
return &ComplexExprEmitter::buildBinDiv;
case BO_SubAssign:
return &ComplexExprEmitter::buildBinSub;
case BO_AddAssign:
return &ComplexExprEmitter::buildBinAdd;
default:
llvm_unreachable("unexpected complex compound assignment");
}
}
LValue CIRGenFunction::buildComplexCompoundAssignmentLValue(
const CompoundAssignOperator *E) {
CompoundFunc Op = getComplexOp(E->getOpcode());
RValue Val;
return ComplexExprEmitter(*this).buildCompoundAssignLValue(E, Op, Val);
}
mlir::Value CIRGenFunction::buildComplexPrePostIncDec(const UnaryOperator *E,
LValue LV, bool isInc,
bool isPre) {
mlir::Value InVal = buildLoadOfComplex(LV, E->getExprLoc());
auto Loc = getLoc(E->getExprLoc());
auto OpKind =
isInc ? mlir::cir::UnaryOpKind::Inc : mlir::cir::UnaryOpKind::Dec;
mlir::Value IncVal = builder.createUnaryOp(Loc, OpKind, InVal);
// Store the updated result through the lvalue.
buildStoreOfComplex(Loc, IncVal, LV, /*init*/ false);
if (getLangOpts().OpenMP)
llvm_unreachable("NYI");
// If this is a postinc, return the value read from memory, otherwise use the
// updated value.
return isPre ? IncVal : InVal;
}
mlir::Value CIRGenFunction::buildLoadOfComplex(LValue src, SourceLocation loc) {
return ComplexExprEmitter(*this).buildLoadOfLValue(src, loc);
}