diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index cba06a1489a29..85cd0282ffc2a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -188,12 +188,6 @@ static const ComplexType *getComplexType(QualType type) { } #endif // NDEBUG -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(), @@ -644,8 +638,12 @@ ComplexExprEmitter::emitPromotedComplexOperand(const Expr *e, return Visit(const_cast(e)); } - cgf.cgm.errorNYI("emitPromotedComplexOperand non-complex type"); - return {}; + if (!promotionTy.isNull()) { + QualType complexElementTy = + promotionTy->castAs()->getElementType(); + return cgf.emitPromotedScalarExpr(e, complexElementTy); + } + return cgf.emitScalarExpr(e); } ComplexExprEmitter::BinOpInfo @@ -690,13 +688,10 @@ LValue ComplexExprEmitter::emitCompoundAssignLValue( // 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)); + opInfo.rhs = cgf.emitPromotedScalarExpr(e->getRHS(), promotionTypeRHS); } else { assert(cgf.getContext().hasSameUnqualifiedType(complexElementTy, rhsTy)); - opInfo.rhs = createComplexFromReal(cgf.getBuilder(), loc, - cgf.emitScalarExpr(e->getRHS())); + opInfo.rhs = cgf.emitScalarExpr(e->getRHS()); } } else { if (!promotionTypeRHS.isNull()) { @@ -716,8 +711,27 @@ LValue ComplexExprEmitter::emitCompoundAssignLValue( QualType destTy = promotionTypeLHS.isNull() ? opInfo.ty : promotionTypeLHS; opInfo.lhs = emitComplexToComplexCast(lhsValue, lhsTy, destTy, exprLoc); } else { - cgf.cgm.errorNYI("emitCompoundAssignLValue emitLoadOfScalar"); - return {}; + 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(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. @@ -759,13 +773,45 @@ mlir::Value ComplexExprEmitter::emitCompoundAssign( mlir::Value ComplexExprEmitter::emitBinAdd(const BinOpInfo &op) { assert(!cir::MissingFeatures::fastMathFlags()); assert(!cir::MissingFeatures::cgFPOptionsRAII()); - return builder.create(op.loc, op.lhs, op.rhs); + + if (mlir::isa(op.lhs.getType()) && + mlir::isa(op.rhs.getType())) + return builder.create(op.loc, op.lhs, op.rhs); + + if (mlir::isa(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(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()); - return builder.create(op.loc, op.lhs, op.rhs); + + if (mlir::isa(op.lhs.getType()) && + mlir::isa(op.rhs.getType())) + return builder.create(op.loc, op.lhs, op.rhs); + + if (mlir::isa(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(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 @@ -788,9 +834,28 @@ getComplexRangeAttr(LangOptions::ComplexRangeKind range) { mlir::Value ComplexExprEmitter::emitBinMul(const BinOpInfo &op) { assert(!cir::MissingFeatures::fastMathFlags()); assert(!cir::MissingFeatures::cgFPOptionsRAII()); - cir::ComplexRangeKind rangeKind = - getComplexRangeAttr(op.fpFeatures.getComplexRange()); - return builder.create(op.loc, op.lhs, op.rhs, rangeKind); + + if (mlir::isa(op.lhs.getType()) && + mlir::isa(op.rhs.getType())) { + cir::ComplexRangeKind rangeKind = + getComplexRangeAttr(op.fpFeatures.getComplexRange()); + return builder.create(op.loc, op.lhs, op.rhs, rangeKind); + } + + if (mlir::isa(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(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); } LValue CIRGenFunction::emitComplexAssignmentLValue(const BinaryOperator *e) { @@ -888,3 +953,12 @@ mlir::Value CIRGenFunction::emitPromotedValue(mlir::Value result, return builder.createCast(cir::CastKind::float_complex, result, convertType(promotionType)); } + +LValue CIRGenFunction::emitScalarCompoundAssignWithComplex( + const CompoundAssignOperator *e, mlir::Value &result) { + CompoundFunc op = getComplexOp(e->getOpcode()); + RValue value; + LValue ret = ComplexExprEmitter(*this).emitCompoundAssignLValue(e, op, value); + result = value.getValue(); + return ret; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 3e06513bb6cf0..d4c7d306cb110 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1066,14 +1066,12 @@ LValue ScalarExprEmitter::emitCompoundAssignLValue( const CompoundAssignOperator *e, mlir::Value (ScalarExprEmitter::*func)(const BinOpInfo &), mlir::Value &result) { + if (e->getComputationResultType()->isAnyComplexType()) + return cgf.emitScalarCompoundAssignWithComplex(e, result); + QualType lhsTy = e->getLHS()->getType(); BinOpInfo opInfo; - if (e->getComputationResultType()->isAnyComplexType()) { - cgf.cgm.errorNYI(result.getLoc(), "complex lvalue assign"); - return LValue(); - } - // Emit the RHS first. __block variables need to have the rhs evaluated // first, plus this should improve codegen a little. diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 065039ec041e0..e5815a054cebd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1100,6 +1100,8 @@ class CIRGenFunction : public CIRGenTypeCache { LValue emitComplexAssignmentLValue(const BinaryOperator *e); LValue emitComplexCompoundAssignmentLValue(const CompoundAssignOperator *e); + LValue emitScalarCompoundAssignWithComplex(const CompoundAssignOperator *e, + mlir::Value &result); void emitCompoundStmt(const clang::CompoundStmt &s); diff --git a/clang/test/CIR/CodeGen/complex-compound-assignment.cpp b/clang/test/CIR/CodeGen/complex-compound-assignment.cpp index 82450259f424b..9a6659bd5d93e 100644 --- a/clang/test/CIR/CodeGen/complex-compound-assignment.cpp +++ b/clang/test/CIR/CodeGen/complex-compound-assignment.cpp @@ -296,26 +296,22 @@ void foo5() { // CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["a"] // CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr, ["b"] // CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr, !cir.float -// CIR: %[[CONST_ZERO:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float -// CIR: %[[COMPLEX_B:.*]] = cir.complex.create %[[TMP_B]], %[[CONST_ZERO]] : !cir.float -> !cir.complex // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr>, !cir.complex -// CIR: %[[RESULT:.*]] = cir.complex.add %[[TMP_A]], %[[COMPLEX_B]] : !cir.complex +// CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex -> !cir.float +// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex -> !cir.float +// CIR: %[[RESULT_REAL:.*]] = cir.binop(add, %[[A_REAL]], %[[TMP_B]]) : !cir.float +// CIR: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[A_IMAG]] : !cir.float -> !cir.complex // CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !cir.complex, !cir.ptr> // LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 // LLVM: %[[B_ADDR:.*]] = alloca float, i64 1, align 4 // LLVM: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 -// LLVM: %[[TMP_COMPLEX_B:.*]] = insertvalue { float, float } {{.*}}, float %[[TMP_B]], 0 -// LLVM: %[[COMPLEX_B:.*]] = insertvalue { float, float } %[[TMP_COMPLEX_B]], float 0.000000e+00, 1 // LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_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 } %[[COMPLEX_B]], 0 -// LLVM: %[[B_IMAG:.*]] = extractvalue { float, float } %[[COMPLEX_B]], 1 -// LLVM: %[[ADD_REAL:.*]] = fadd float %[[A_REAL]], %[[B_REAL]] -// LLVM: %[[ADD_IMAG:.*]] = fadd float %[[A_IMAG]], %[[B_IMAG]] -// LLVM: %[[TMP_RESULT:.*]] = insertvalue { float, float } poison, float %[[ADD_REAL]], 0 -// LLVM: %[[RESULT:.*]] = insertvalue { float, float } %[[TMP_RESULT]], float %[[ADD_IMAG]], 1 +// LLVM: %[[RESULT_REAL:.*]] = fadd float %[[A_REAL]], %[[TMP_B]] +// LLVM: %[[TMP_RESULT:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL]], 0 +// LLVM: %[[RESULT:.*]] = insertvalue { float, float } %[[TMP_RESULT]], float %[[A_IMAG]], 1 // LLVM: store { float, float } %[[RESULT]], ptr %[[A_ADDR]], align 4 // OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4 @@ -494,3 +490,85 @@ void foo7() { // OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1 // OGCG: store float %[[FINAL_REAL]], ptr %[[C_REAL_PTR]], align 4 // OGCG: store float %[[FINAL_IMAG]], ptr %[[C_IMAG_PTR]], align 4 + +void foo8() { + float _Complex a; + float b; + a *= b; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr, ["b"] +// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr, !cir.float +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr>, !cir.complex +// CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex -> !cir.float +// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex -> !cir.float +// CIR: %[[RESULT_REAL:.*]] = cir.binop(mul, %[[A_REAL]], %[[TMP_B]]) : !cir.float +// CIR: %[[RESULT_IMAG:.*]] = cir.binop(mul, %[[A_IMAG]], %[[TMP_B]]) : !cir.float +// CIR: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !cir.float -> !cir.complex +// CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !cir.complex, !cir.ptr> + +// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: %[[B_ADDR:.*]] = alloca float, i64 1, align 4 +// LLVM: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 +// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1 +// LLVM: %[[RESULT_REAL:.*]] = fmul float %[[A_REAL]], %[[TMP_B]] +// LLVM: %[[RESULT_IMAG:.*]] = fmul float %[[A_IMAG]], %[[TMP_B]] +// LLVM: %[[TMP_RESULT:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL]], 0 +// LLVM: %[[RESULT:.*]] = insertvalue { float, float } %[[TMP_RESULT]], float %[[RESULT_IMAG]], 1 +// LLVM: store { float, float } %[[RESULT]], ptr %[[A_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[B_ADDR:.*]] = alloca float, align 4 +// OGCG: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 +// 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 %[[A_ADDR]], i32 0, i32 1 +// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4 +// OGCG: %[[RESULT_REAL:.*]] = fmul float %[[A_REAL]], %[[TMP_B]] +// OGCG: %[[RESULT_IMAG:.*]] = fmul float %[[A_IMAG]], %[[TMP_B]] +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG: store float %[[RESULT_REAL]], ptr %[[A_REAL_PTR]], align 4 +// OGCG: store float %[[RESULT_IMAG]], ptr %[[A_IMAG_PTR]], align 4 + +#ifndef __cplusplus +void foo9() { + float _Complex a; + float b; + b += a; +} +#endif + +// C_CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["a"] +// C_CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr, ["b"] +// C_CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr>, !cir.complex +// C_CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr, !cir.float +// C_CIR: %[[A_REAL:.*]] = cir.complex.real %[[A_ADDR]] : !cir.complex -> !cir.float +// C_CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[A_ADDR]] : !cir.complex -> !cir.float +// C_CIR: %[[NEW_REAL:.*]] = cir.binop(add, %[[TMP_B]], %[[A_REAL]]) : !cir.float +// C_CIR: %[[RESULT:.*]] = cir.complex.create %[[NEW_REAL]], %[[A_IMAG]] : !cir.float -> !cir.complex +// C_CIR: %[[RESULT_REAL:.*]] = cir.complex.real %[[RESULT]] : !cir.complex -> !cir.float +// C_CIR: cir.store{{.*}} %[[RESULT_REAL]], %[[B_ADDR]] : !cir.float, !cir.ptr + +// C_LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// C_LLVM: %[[B_ADDR:.*]] = alloca float, i64 1, align 4 +// C_LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// C_LLVM: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 +// C_LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// C_LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1 +// C_LLVM: %[[NEW_REAL:.*]] = fadd float %[[TMP_B]], %[[A_REAL]] +// C_LLVM: %[[TMP_RESULT:.*]] = insertvalue { float, float } {{.*}}, float %[[NEW_REAL]], 0 +// C_LLVM: store float %[[NEW_REAL]], ptr %[[B_ADDR]], align 4 + +// C_OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// C_OGCG: %[[B_ADDR:.*]] = alloca float, align 4 +// C_OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// C_OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// C_OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// C_OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4 +// C_OGCG: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 +// C_OGCG: %[[ADD_REAL:.*]] = fadd float %[[TMP_B]], %[[A_REAL]] +// C_OGCG: store float %[[ADD_REAL]], ptr %[[B_ADDR]], align 4 diff --git a/clang/test/CIR/CodeGen/complex-mul-div.cpp b/clang/test/CIR/CodeGen/complex-mul-div.cpp index 9d71ef7453001..633080577092c 100644 --- a/clang/test/CIR/CodeGen/complex-mul-div.cpp +++ b/clang/test/CIR/CodeGen/complex-mul-div.cpp @@ -1,38 +1,38 @@ // complex-range basic // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -complex-range=basic -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE-BASIC %s // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=basic -Wno-unused-value -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-INT,CIR-AFTER-MUL-COMBINED +// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-INT,CIR-AFTER-MUL-COMBINED,CIR-COMBINED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=basic -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-INT,LLVM-MUL-COMBINED +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-INT,LLVM-MUL-COMBINED,LLVM-COMBINED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=basic -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-INT,OGCG-MUL-COMBINED +// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-INT,OGCG-MUL-COMBINED,OGCG-COMBINED // complex-range improved // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -complex-range=improved -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE-IMPROVED %s // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=improved -Wno-unused-value -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-INT,CIR-AFTER-MUL-COMBINED +// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-INT,CIR-AFTER-MUL-COMBINED,CIR-COMBINED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=improved -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-INT,LLVM-MUL-COMBINED +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-INT,LLVM-MUL-COMBINED,LLVM-COMBINED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=improved -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-INT,OGCG-MUL-COMBINED +// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-INT,OGCG-MUL-COMBINED,OGCG-COMBINED // complex-range promoted // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -complex-range=promoted -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE-PROMOTED %s // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=promoted -Wno-unused-value -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-INT,CIR-AFTER-MUL-COMBINED +// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-INT,CIR-AFTER-MUL-COMBINED,CIR-COMBINED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=promoted -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-INT,LLVM-MUL-COMBINED +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-INT,LLVM-MUL-COMBINED,LLVM-COMBINED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=promoted -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-INT,OGCG-MUL-COMBINED +// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-INT,OGCG-MUL-COMBINED,OGCG-COMBINED // complex-range full // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -complex-range=full -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE-FULL %s // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=full -Wno-unused-value -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-FULL,CIR-AFTER-INT +// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-FULL,CIR-AFTER-INT,CIR-COMBINED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=full -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-FULL,LLVM-INT +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-FULL,LLVM-INT,LLVM-COMBINED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=full -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-FULL,OGCG-INT +// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-FULL,OGCG-INT,OGCG-COMBINED void foo() { float _Complex a; @@ -278,3 +278,49 @@ void foo1() { // OGCG-INT: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[C_ADDR]], i32 0, i32 1 // OGCG-INT: store i32 %[[C_REAL]], ptr %[[C_REAL_PTR]], align 4 // OGCG-INT: store i32 %[[C_IMAG]], ptr %[[C_IMAG_PTR]], align 4 + +void foo2() { + float _Complex a; + float b; + float _Complex c = a * b; +} + +// CIR-COMBINED: %[[A_ADDR:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["a"] +// CIR-COMBINED: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr, ["b"] +// CIR-COMBINED: %[[C_ADDR:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["c", init] +// CIR-COMBINED: %[[TMP_A:.*]] = cir.load{{.*}} %0 : !cir.ptr>, !cir.complex +// CIR-COMBINED: %[[TMP_B:.*]] = cir.load{{.*}} %1 : !cir.ptr, !cir.float +// CIR-COMBINED: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex -> !cir.float +// CIR-COMBINED: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex -> !cir.float +// CIR-COMBINED: %[[RESULT_REAL:.*]] = cir.binop(mul, %[[A_REAL]], %[[TMP_B]]) : !cir.float +// CIR-COMBINED: %[[RESULT_IMAG:.*]] = cir.binop(mul, %[[A_IMAG]], %[[TMP_B]]) : !cir.float +// CIR-COMBINED: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !cir.float -> !cir.complex +// CIR-COMBINED: cir.store{{.*}} %[[RESULT]], %[[C_ADDR]] : !cir.complex, !cir.ptr> + +// LLVM-COMBINED: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-COMBINED: %[[B_ADDR:.*]] = alloca float, i64 1, align 4 +// LLVM-COMBINED: %[[C_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-COMBINED: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// LLVM-COMBINED: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 +// LLVM-COMBINED: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM-COMBINED: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1 +// LLVM-COMBINED: %[[RESULT_REAL:.*]] = fmul float %[[A_REAL]], %[[TMP_B]] +// LLVM-COMBINED: %[[RESULT_IMAG:.*]] = fmul float %[[A_IMAG]], %[[TMP_B]] +// LLVM-COMBINED: %[[TMP_RESULT:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL]], 0 +// LLVM-COMBINED: %[[RESULT:.*]] = insertvalue { float, float } %[[TMP_RESULT]], float %[[RESULT_IMAG]], 1 +// LLVM-COMBINED: store { float, float } %[[RESULT]], ptr %[[C_ADDR]], align 4 + +// OGCG-COMBINED: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-COMBINED: %[[B_ADDR:.*]] = alloca float, align 4 +// OGCG-COMBINED: %[[C_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-COMBINED: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG-COMBINED: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// OGCG-COMBINED: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG-COMBINED: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4 +// OGCG-COMBINED: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 +// OGCG-COMBINED: %[[RESULT_REAL:.*]] = fmul float %[[A_REAL]], %[[TMP_B]] +// OGCG-COMBINED: %[[RESULT_IMAG:.*]] = fmul float %[[A_IMAG]], %[[TMP_B]] +// OGCG-COMBINED: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 0 +// OGCG-COMBINED: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 1 +// OGCG-COMBINED: store float %[[RESULT_REAL]], ptr %[[C_REAL_PTR]], align 4 +// OGCG-COMBINED: store float %[[RESULT_IMAG]], ptr %[[C_IMAG_PTR]], align 4