-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[CIR] Plus & Minus CompoundAssignment support for ComplexType #150759
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[CIR] Plus & Minus CompoundAssignment support for ComplexType #150759
Conversation
@llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) ChangesThis change adds support for Plus & Minus CompoundAssignment for ComplexType Patch is 44.04 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/150759.diff 5 Files Affected:
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index 02685a3d64121..f80ced3e7924e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -108,6 +108,15 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
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);
@@ -143,6 +152,15 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
HANDLEBINOP(Add)
HANDLEBINOP(Sub)
#undef HANDLEBINOP
+
+ // Compound assignments.
+ mlir::Value VisitBinAddAssign(const CompoundAssignOperator *e) {
+ return emitCompoundAssign(e, &ComplexExprEmitter::emitBinAdd);
+ }
+
+ mlir::Value VisitBinSubAssign(const CompoundAssignOperator *e) {
+ return emitCompoundAssign(e, &ComplexExprEmitter::emitBinSub);
+ }
};
} // namespace
@@ -153,6 +171,12 @@ static const ComplexType *getComplexType(QualType type) {
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);
+}
+
LValue ComplexExprEmitter::emitBinAssignLValue(const BinaryOperator *e,
mlir::Value &value) {
assert(cgf.getContext().hasSameUnqualifiedType(e->getLHS()->getType(),
@@ -570,6 +594,124 @@ ComplexExprEmitter::emitBinOps(const BinaryOperator *e, QualType promotionTy) {
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 (const AtomicType *atomicTy = lhsTy->getAs<AtomicType>())
+ lhsTy = atomicTy->getValueType();
+
+ 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 = createComplexFromReal(
+ cgf.getBuilder(), loc,
+ cgf.emitPromotedScalarExpr(e->getRHS(), promotionTypeRHS));
+ else {
+ assert(cgf.getContext().hasSameUnqualifiedType(complexElementTy, rhsTy));
+ opInfo.rhs = createComplexFromReal(cgf.getBuilder(), loc,
+ cgf.emitScalarExpr(e->getRHS()));
+ }
+ } else {
+ if (!promotionTypeRHS.isNull()) {
+ opInfo.rhs = createComplexFromReal(
+ cgf.getBuilder(), loc,
+ 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 lhsValue = 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))
+ lhsValue = cgf.emitScalarConversion(
+ lhsValue, lhsTy, promotedComplexElementTy, exprLoc);
+ } else {
+ if (!cgf.getContext().hasSameUnqualifiedType(complexElementTy, lhsTy))
+ lhsValue = cgf.emitScalarConversion(lhsValue, lhsTy, complexElementTy,
+ exprLoc);
+ }
+ opInfo.lhs = createComplexFromReal(cgf.getBuilder(),
+ cgf.getLoc(e->getExprLoc()), lhsValue);
+ } else {
+ opInfo.lhs = emitScalarToComplexCast(lhsValue, 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());
+}
+
mlir::Value ComplexExprEmitter::emitBinAdd(const BinOpInfo &op) {
assert(!cir::MissingFeatures::fastMathFlags());
assert(!cir::MissingFeatures::cgFPOptionsRAII());
@@ -600,6 +742,31 @@ mlir::Value CIRGenFunction::emitComplexExpr(const Expr *e) {
return ComplexExprEmitter(*this).Visit(const_cast<Expr *>(e));
}
+using CompoundFunc =
+ mlir::Value (ComplexExprEmitter::*)(const ComplexExprEmitter::BinOpInfo &);
+
+static CompoundFunc getComplexOp(BinaryOperatorKind Op) {
+ switch (Op) {
+ case BO_MulAssign:
+ llvm_unreachable("getComplexOp: BO_MulAssign");
+ case BO_DivAssign:
+ llvm_unreachable("getComplexOp: BO_DivAssign");
+ 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,
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 2523b0ff33787..688d74d2174f2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -1931,6 +1931,29 @@ mlir::Value CIRGenFunction::emitScalarConversion(mlir::Value src,
.emitScalarConversion(src, srcTy, dstTy, loc);
}
+mlir::Value CIRGenFunction::emitComplexToScalarConversion(mlir::Value src,
+ QualType srcTy,
+ QualType dstTy,
+ SourceLocation loc) {
+ assert(srcTy->isAnyComplexType() && hasScalarEvaluationKind(dstTy) &&
+ "Invalid complex -> scalar conversion");
+
+ QualType complexElemTy = srcTy->castAs<ComplexType>()->getElementType();
+ if (dstTy->isBooleanType()) {
+ auto kind = complexElemTy->isFloatingType()
+ ? cir::CastKind::float_complex_to_bool
+ : cir::CastKind::int_complex_to_bool;
+ return builder.createCast(getLoc(loc), kind, src, convertType(dstTy));
+ }
+
+ auto kind = complexElemTy->isFloatingType()
+ ? cir::CastKind::float_complex_to_real
+ : cir::CastKind::int_complex_to_real;
+ mlir::Value real =
+ builder.createCast(getLoc(loc), kind, src, convertType(complexElemTy));
+ return emitScalarConversion(real, complexElemTy, dstTy, loc);
+}
+
mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *e) {
// Perform vector logical not on comparison with zero vector.
if (e->getType()->isVectorType() &&
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index b4b95d627c619..2193092eea174 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -783,9 +783,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
}
if (!ty->isAnyComplexType())
return emitCompoundAssignmentLValue(cast<CompoundAssignOperator>(e));
- cgm.errorNYI(e->getSourceRange(),
- "CompoundAssignOperator with ComplexType");
- return LValue();
+
+ return emitComplexCompoundAssignmentLValue(cast<CompoundAssignOperator>(e));
}
case Expr::CallExprClass:
case Expr::CXXMemberCallExprClass:
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 4891c7496588f..915efa552fc3c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -918,6 +918,11 @@ class CIRGenFunction : public CIRGenTypeCache {
/// sanitizer is enabled, a runtime check is also emitted.
mlir::Value emitCheckedArgForAssume(const Expr *e);
+ /// Emit a conversion from the specified complex type to the specified
+ /// destination type, where the destination type is an LLVM scalar type.
+ mlir::Value emitComplexToScalarConversion(mlir::Value src, QualType srcTy,
+ QualType dstTy, SourceLocation loc);
+
LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e);
LValue emitCompoundLiteralLValue(const CompoundLiteralExpr *e);
@@ -1050,6 +1055,7 @@ class CIRGenFunction : public CIRGenTypeCache {
cir::UnaryOpKind op, bool isPre);
LValue emitComplexAssignmentLValue(const BinaryOperator *e);
+ LValue emitComplexCompoundAssignmentLValue(const CompoundAssignOperator *e);
void emitCompoundStmt(const clang::CompoundStmt &s);
diff --git a/clang/test/CIR/CodeGen/complex-arithmetic.cpp b/clang/test/CIR/CodeGen/complex-arithmetic.cpp
index 5e384cd34ebfd..657b9dafd7b9d 100644
--- a/clang/test/CIR/CodeGen/complex-arithmetic.cpp
+++ b/clang/test/CIR/CodeGen/complex-arithmetic.cpp
@@ -11,16 +11,16 @@ void foo() {
int _Complex c = a + b;
}
-// CIR: %[[COMPLEX_A:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
-// CIR: %[[COMPLEX_B:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b"]
-// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[COMPLEX_A]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
-// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[COMPLEX_B]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b"]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
// CIR: %[[ADD:.*]] = cir.complex.add %[[TMP_A]], %[[TMP_B]] : !cir.complex<!s32i>
-// LLVM: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, i64 1, align 4
-// LLVM: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, i64 1, align 4
-// LLVM: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[COMPLEX_A]], align 4
-// LLVM: %[[TMP_B:.*]] = load { i32, i32 }, ptr %[[COMPLEX_B]], align 4
+// LLVM: %[[A_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[B_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[A_ADDR]], align 4
+// LLVM: %[[TMP_B:.*]] = load { i32, i32 }, ptr %[[B_ADDR]], align 4
// LLVM: %[[A_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 0
// LLVM: %[[A_IMAG:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 1
// LLVM: %[[B_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_B]], 0
@@ -30,16 +30,16 @@ void foo() {
// LLVM: %[[RESULT:.*]] = insertvalue { i32, i32 } poison, i32 %[[ADD_REAL]], 0
// LLVM: %[[RESULT_2:.*]] = insertvalue { i32, i32 } %[[RESULT]], i32 %[[ADD_IMAG]], 1
-// OGCG: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, align 4
-// OGCG: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[A_ADDR:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[B_ADDR:.*]] = alloca { i32, i32 }, align 4
// OGCG: %[[RESULT:.*]] = alloca { i32, i32 }, align 4
-// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 0
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 0
// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4
-// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 1
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 1
// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4
-// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 0
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 0
// OGCG: %[[B_REAL:.*]] = load i32, ptr %[[B_REAL_PTR]], align 4
-// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 1
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 1
// OGCG: %[[B_IMAG:.*]] = load i32, ptr %[[B_IMAG_PTR]], align 4
// OGCG: %[[ADD_REAL:.*]] = add i32 %[[A_REAL]], %[[B_REAL]]
// OGCG: %[[ADD_IMAG:.*]] = add i32 %[[A_IMAG]], %[[B_IMAG]]
@@ -54,16 +54,16 @@ void foo2() {
float _Complex c = a + b;
}
-// CIR: %[[COMPLEX_A:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
-// CIR: %[[COMPLEX_B:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
-// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[COMPLEX_A]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
-// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[COMPLEX_B]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
// CIR: %[[ADD:.*]] = cir.complex.add %[[TMP_A]], %[[TMP_B]] : !cir.complex<!cir.float>
-// LLVM: %[[COMPLEX_A:.*]] = alloca { float, float }, i64 1, align 4
-// LLVM: %[[COMPLEX_B:.*]] = alloca { float, float }, i64 1, align 4
-// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[COMPLEX_A]], align 4
-// LLVM: %[[TMP_B:.*]] = load { float, float }, ptr %[[COMPLEX_B]], align 4
+// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4
+// LLVM: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4
// LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0
// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1
// LLVM: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0
@@ -73,16 +73,16 @@ void foo2() {
// LLVM: %[[RESULT:.*]] = insertvalue { float, float } poison, float %[[ADD_REAL]], 0
// LLVM: %[[RESULT_2:.*]] = insertvalue { float, float } %[[RESULT]], float %[[ADD_IMAG]], 1
-// OGCG: %[[COMPLEX_A:.*]] = alloca { float, float }, align 4
-// OGCG: %[[COMPLEX_B:.*]] = alloca { float, float }, align 4
+// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: %[[B_ADDR:.*]] = alloca { float, float }, align 4
// OGCG: %[[RESULT:.*]] = alloca { float, float }, align 4
-// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX_A]], i32 0, i32 0
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4
-// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX_A]], i32 0, i32 1
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4
-// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX_B]], i32 0, i32 0
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0
// OGCG: %[[B_REAL:.*]] = load float, ptr %[[B_REAL_PTR]], align 4
-// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX_B]], i32 0, i32 1
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
// OGCG: %[[B_IMAG:.*]] = load float, ptr %[[B_IMAG_PTR]], align 4
// OGCG: %[[ADD_REAL:.*]] = fadd float %[[A_REAL]], %[[B_REAL]]
// OGCG: %[[ADD_IMAG:.*]] = fadd float %[[A_IMAG]], %[[B_IMAG]]
@@ -98,23 +98,23 @@ void foo3() {
float _Complex d = (a + b) + c;
}
-// CIR: %[[COMPLEX_A:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
-// CIR: %[[COMPLEX_B:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
-// CIR: %[[COMPLEX_C:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c"]
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
+// CIR: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c"]
// CIR: %[[RESULT:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["d", init]
-// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[COMPLEX_A]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
-// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[COMPLEX_B]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!ci...
[truncated]
|
@llvm/pr-subscribers-clang Author: Amr Hesham (AmrDeveloper) ChangesThis change adds support for Plus & Minus CompoundAssignment for ComplexType Patch is 44.04 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/150759.diff 5 Files Affected:
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index 02685a3d64121..f80ced3e7924e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -108,6 +108,15 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
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);
@@ -143,6 +152,15 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
HANDLEBINOP(Add)
HANDLEBINOP(Sub)
#undef HANDLEBINOP
+
+ // Compound assignments.
+ mlir::Value VisitBinAddAssign(const CompoundAssignOperator *e) {
+ return emitCompoundAssign(e, &ComplexExprEmitter::emitBinAdd);
+ }
+
+ mlir::Value VisitBinSubAssign(const CompoundAssignOperator *e) {
+ return emitCompoundAssign(e, &ComplexExprEmitter::emitBinSub);
+ }
};
} // namespace
@@ -153,6 +171,12 @@ static const ComplexType *getComplexType(QualType type) {
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);
+}
+
LValue ComplexExprEmitter::emitBinAssignLValue(const BinaryOperator *e,
mlir::Value &value) {
assert(cgf.getContext().hasSameUnqualifiedType(e->getLHS()->getType(),
@@ -570,6 +594,124 @@ ComplexExprEmitter::emitBinOps(const BinaryOperator *e, QualType promotionTy) {
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 (const AtomicType *atomicTy = lhsTy->getAs<AtomicType>())
+ lhsTy = atomicTy->getValueType();
+
+ 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 = createComplexFromReal(
+ cgf.getBuilder(), loc,
+ cgf.emitPromotedScalarExpr(e->getRHS(), promotionTypeRHS));
+ else {
+ assert(cgf.getContext().hasSameUnqualifiedType(complexElementTy, rhsTy));
+ opInfo.rhs = createComplexFromReal(cgf.getBuilder(), loc,
+ cgf.emitScalarExpr(e->getRHS()));
+ }
+ } else {
+ if (!promotionTypeRHS.isNull()) {
+ opInfo.rhs = createComplexFromReal(
+ cgf.getBuilder(), loc,
+ 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 lhsValue = 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))
+ lhsValue = cgf.emitScalarConversion(
+ lhsValue, lhsTy, promotedComplexElementTy, exprLoc);
+ } else {
+ if (!cgf.getContext().hasSameUnqualifiedType(complexElementTy, lhsTy))
+ lhsValue = cgf.emitScalarConversion(lhsValue, lhsTy, complexElementTy,
+ exprLoc);
+ }
+ opInfo.lhs = createComplexFromReal(cgf.getBuilder(),
+ cgf.getLoc(e->getExprLoc()), lhsValue);
+ } else {
+ opInfo.lhs = emitScalarToComplexCast(lhsValue, 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());
+}
+
mlir::Value ComplexExprEmitter::emitBinAdd(const BinOpInfo &op) {
assert(!cir::MissingFeatures::fastMathFlags());
assert(!cir::MissingFeatures::cgFPOptionsRAII());
@@ -600,6 +742,31 @@ mlir::Value CIRGenFunction::emitComplexExpr(const Expr *e) {
return ComplexExprEmitter(*this).Visit(const_cast<Expr *>(e));
}
+using CompoundFunc =
+ mlir::Value (ComplexExprEmitter::*)(const ComplexExprEmitter::BinOpInfo &);
+
+static CompoundFunc getComplexOp(BinaryOperatorKind Op) {
+ switch (Op) {
+ case BO_MulAssign:
+ llvm_unreachable("getComplexOp: BO_MulAssign");
+ case BO_DivAssign:
+ llvm_unreachable("getComplexOp: BO_DivAssign");
+ 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,
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 2523b0ff33787..688d74d2174f2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -1931,6 +1931,29 @@ mlir::Value CIRGenFunction::emitScalarConversion(mlir::Value src,
.emitScalarConversion(src, srcTy, dstTy, loc);
}
+mlir::Value CIRGenFunction::emitComplexToScalarConversion(mlir::Value src,
+ QualType srcTy,
+ QualType dstTy,
+ SourceLocation loc) {
+ assert(srcTy->isAnyComplexType() && hasScalarEvaluationKind(dstTy) &&
+ "Invalid complex -> scalar conversion");
+
+ QualType complexElemTy = srcTy->castAs<ComplexType>()->getElementType();
+ if (dstTy->isBooleanType()) {
+ auto kind = complexElemTy->isFloatingType()
+ ? cir::CastKind::float_complex_to_bool
+ : cir::CastKind::int_complex_to_bool;
+ return builder.createCast(getLoc(loc), kind, src, convertType(dstTy));
+ }
+
+ auto kind = complexElemTy->isFloatingType()
+ ? cir::CastKind::float_complex_to_real
+ : cir::CastKind::int_complex_to_real;
+ mlir::Value real =
+ builder.createCast(getLoc(loc), kind, src, convertType(complexElemTy));
+ return emitScalarConversion(real, complexElemTy, dstTy, loc);
+}
+
mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *e) {
// Perform vector logical not on comparison with zero vector.
if (e->getType()->isVectorType() &&
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index b4b95d627c619..2193092eea174 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -783,9 +783,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
}
if (!ty->isAnyComplexType())
return emitCompoundAssignmentLValue(cast<CompoundAssignOperator>(e));
- cgm.errorNYI(e->getSourceRange(),
- "CompoundAssignOperator with ComplexType");
- return LValue();
+
+ return emitComplexCompoundAssignmentLValue(cast<CompoundAssignOperator>(e));
}
case Expr::CallExprClass:
case Expr::CXXMemberCallExprClass:
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 4891c7496588f..915efa552fc3c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -918,6 +918,11 @@ class CIRGenFunction : public CIRGenTypeCache {
/// sanitizer is enabled, a runtime check is also emitted.
mlir::Value emitCheckedArgForAssume(const Expr *e);
+ /// Emit a conversion from the specified complex type to the specified
+ /// destination type, where the destination type is an LLVM scalar type.
+ mlir::Value emitComplexToScalarConversion(mlir::Value src, QualType srcTy,
+ QualType dstTy, SourceLocation loc);
+
LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e);
LValue emitCompoundLiteralLValue(const CompoundLiteralExpr *e);
@@ -1050,6 +1055,7 @@ class CIRGenFunction : public CIRGenTypeCache {
cir::UnaryOpKind op, bool isPre);
LValue emitComplexAssignmentLValue(const BinaryOperator *e);
+ LValue emitComplexCompoundAssignmentLValue(const CompoundAssignOperator *e);
void emitCompoundStmt(const clang::CompoundStmt &s);
diff --git a/clang/test/CIR/CodeGen/complex-arithmetic.cpp b/clang/test/CIR/CodeGen/complex-arithmetic.cpp
index 5e384cd34ebfd..657b9dafd7b9d 100644
--- a/clang/test/CIR/CodeGen/complex-arithmetic.cpp
+++ b/clang/test/CIR/CodeGen/complex-arithmetic.cpp
@@ -11,16 +11,16 @@ void foo() {
int _Complex c = a + b;
}
-// CIR: %[[COMPLEX_A:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
-// CIR: %[[COMPLEX_B:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b"]
-// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[COMPLEX_A]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
-// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[COMPLEX_B]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b"]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
// CIR: %[[ADD:.*]] = cir.complex.add %[[TMP_A]], %[[TMP_B]] : !cir.complex<!s32i>
-// LLVM: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, i64 1, align 4
-// LLVM: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, i64 1, align 4
-// LLVM: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[COMPLEX_A]], align 4
-// LLVM: %[[TMP_B:.*]] = load { i32, i32 }, ptr %[[COMPLEX_B]], align 4
+// LLVM: %[[A_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[B_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[A_ADDR]], align 4
+// LLVM: %[[TMP_B:.*]] = load { i32, i32 }, ptr %[[B_ADDR]], align 4
// LLVM: %[[A_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 0
// LLVM: %[[A_IMAG:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 1
// LLVM: %[[B_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_B]], 0
@@ -30,16 +30,16 @@ void foo() {
// LLVM: %[[RESULT:.*]] = insertvalue { i32, i32 } poison, i32 %[[ADD_REAL]], 0
// LLVM: %[[RESULT_2:.*]] = insertvalue { i32, i32 } %[[RESULT]], i32 %[[ADD_IMAG]], 1
-// OGCG: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, align 4
-// OGCG: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[A_ADDR:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[B_ADDR:.*]] = alloca { i32, i32 }, align 4
// OGCG: %[[RESULT:.*]] = alloca { i32, i32 }, align 4
-// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 0
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 0
// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4
-// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 1
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 1
// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4
-// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 0
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 0
// OGCG: %[[B_REAL:.*]] = load i32, ptr %[[B_REAL_PTR]], align 4
-// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 1
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 1
// OGCG: %[[B_IMAG:.*]] = load i32, ptr %[[B_IMAG_PTR]], align 4
// OGCG: %[[ADD_REAL:.*]] = add i32 %[[A_REAL]], %[[B_REAL]]
// OGCG: %[[ADD_IMAG:.*]] = add i32 %[[A_IMAG]], %[[B_IMAG]]
@@ -54,16 +54,16 @@ void foo2() {
float _Complex c = a + b;
}
-// CIR: %[[COMPLEX_A:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
-// CIR: %[[COMPLEX_B:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
-// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[COMPLEX_A]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
-// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[COMPLEX_B]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
// CIR: %[[ADD:.*]] = cir.complex.add %[[TMP_A]], %[[TMP_B]] : !cir.complex<!cir.float>
-// LLVM: %[[COMPLEX_A:.*]] = alloca { float, float }, i64 1, align 4
-// LLVM: %[[COMPLEX_B:.*]] = alloca { float, float }, i64 1, align 4
-// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[COMPLEX_A]], align 4
-// LLVM: %[[TMP_B:.*]] = load { float, float }, ptr %[[COMPLEX_B]], align 4
+// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4
+// LLVM: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4
// LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0
// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1
// LLVM: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0
@@ -73,16 +73,16 @@ void foo2() {
// LLVM: %[[RESULT:.*]] = insertvalue { float, float } poison, float %[[ADD_REAL]], 0
// LLVM: %[[RESULT_2:.*]] = insertvalue { float, float } %[[RESULT]], float %[[ADD_IMAG]], 1
-// OGCG: %[[COMPLEX_A:.*]] = alloca { float, float }, align 4
-// OGCG: %[[COMPLEX_B:.*]] = alloca { float, float }, align 4
+// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: %[[B_ADDR:.*]] = alloca { float, float }, align 4
// OGCG: %[[RESULT:.*]] = alloca { float, float }, align 4
-// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX_A]], i32 0, i32 0
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4
-// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX_A]], i32 0, i32 1
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4
-// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX_B]], i32 0, i32 0
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0
// OGCG: %[[B_REAL:.*]] = load float, ptr %[[B_REAL_PTR]], align 4
-// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX_B]], i32 0, i32 1
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
// OGCG: %[[B_IMAG:.*]] = load float, ptr %[[B_IMAG_PTR]], align 4
// OGCG: %[[ADD_REAL:.*]] = fadd float %[[A_REAL]], %[[B_REAL]]
// OGCG: %[[ADD_IMAG:.*]] = fadd float %[[A_IMAG]], %[[B_IMAG]]
@@ -98,23 +98,23 @@ void foo3() {
float _Complex d = (a + b) + c;
}
-// CIR: %[[COMPLEX_A:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
-// CIR: %[[COMPLEX_B:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
-// CIR: %[[COMPLEX_C:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c"]
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
+// CIR: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c"]
// CIR: %[[RESULT:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["d", init]
-// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[COMPLEX_A]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
-// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[COMPLEX_B]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!ci...
[truncated]
|
SourceLocation exprLoc = e->getExprLoc(); | ||
mlir::Location loc = cgf.getLoc(exprLoc); | ||
|
||
if (const AtomicType *atomicTy = lhsTy->getAs<AtomicType>()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like this should be an errorNYI
condition. I guess we'll hit an NYI diagnostic somewhere else, but this won't actually work. What I've been doing in cases like this is leaving the final code, but also adding an errorNYI
call and a comment explaining that the code is correct but is expected to be NYI somewhere else.
|
||
// The RHS should have been converted to the computation type. | ||
if (e->getRHS()->getType()->isRealFloatingType()) { | ||
if (!promotionTypeRHS.isNull()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The if
clause should have braces since the else
clause requires them.
} | ||
} else { | ||
if (!promotionTypeRHS.isNull()) { | ||
opInfo.rhs = createComplexFromReal( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should be calling createComplexFromReal
here. We checked on line 625 that RHS is not a real type. I think this was a bug in the incubator.
QualType destTy = promotionTypeLHS.isNull() ? opInfo.ty : promotionTypeLHS; | ||
opInfo.lhs = emitComplexToComplexCast(lhsValue, lhsTy, destTy, exprLoc); | ||
} else { | ||
mlir::Value lhsValue = cgf.emitLoadOfScalar(lhs, exprLoc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to get here? The code below results in error: assigning to 'float' from incompatible type '_Complex float'
float x;
float _Complex y;
void bar() {
x += y;
}
value = RValue::getComplex(resultValue); | ||
} else { | ||
mlir::Value resultValue = | ||
cgf.emitComplexToScalarConversion(result, opInfo.ty, lhsTy, exprLoc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emitComplexToScalarConversion
starts by asserting that the src type is a complex type, so if we get here the code will assert.
// OGCG: %[[C_IMAG:.*]] = load float, ptr %[[C_IMAG_PTR]], align 4 | ||
// OGCG: %[[SUB_REAL_A_B_C:.*]] = fsub float %[[SUB_REAL_A_B]], %[[C_REAL]] | ||
// OGCG: %[[SUB_IMAG_A_B_C:.*]] = fsub float %[[SUB_IMAG_A_B]], %[[C_IMAG]] | ||
// OGCG: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RESULT]], i32 0, i32 0 | ||
// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RESULT]], i32 0, i32 1 | ||
// OGCG: store float %[[SUB_REAL_A_B_C]], ptr %[[RESULT_REAL_PTR]], align 4 | ||
// OGCG: store float %[[SUB_IMAG_A_B_C]], ptr %[[RESULT_IMAG_PTR]], align 4 | ||
|
||
void foo7() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add tests for _Float16 _Complex
and int _Complex
?
Also, you need a C test to exercise the difference in behavior between C and C++. If you put the compound assignment in a separate test, you can test C and C++ by adding an extra RUN line with -x c
and making it a .cpp file.
This change adds support for Plus & Minus CompoundAssignment for ComplexType
#141365