Author: Amr Hesham
Date: 2026-08-05T04:21:27Z
New Revision: 442469093a0ea00244b39dfb8ab26545439fe363

URL: 
https://github.com/llvm/llvm-project/commit/442469093a0ea00244b39dfb8ab26545439fe363
DIFF: 
https://github.com/llvm/llvm-project/commit/442469093a0ea00244b39dfb8ab26545439fe363.diff

LOG: [CIR] Fix imag value in Scalar and Complex substraction (#214019)

Fix imaginary value in Scalar and Complex subtraction

Issue #213998

Added: 
    

Modified: 
    clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
    clang/test/CIR/CodeGen/complex-plus-minus.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index 2d99d3111e903..8780122ee2db2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -666,11 +666,17 @@ mlir::Value ComplexExprEmitter::emitBinSub(const 
BinOpInfo &op) {
     return builder.createComplexCreate(op.loc, newReal, imag);
   }
 
+  auto createNeg = [&](mlir::Location loc, mlir::Value a) {
+    return cir::isFPOrVectorOfFPType(a.getType()) ? builder.createFNeg(loc, a)
+                                                  : builder.createNeg(loc, a);
+  };
+
   assert(mlir::isa<cir::ComplexType>(op.rhs.getType()));
   mlir::Value real = builder.createComplexReal(op.loc, op.rhs);
   mlir::Value imag = builder.createComplexImag(op.loc, op.rhs);
   mlir::Value newReal = createSub(op.loc, op.lhs, real);
-  return builder.createComplexCreate(op.loc, newReal, imag);
+  mlir::Value newImag = createNeg(op.loc, imag);
+  return builder.createComplexCreate(op.loc, newReal, newImag);
 }
 
 static cir::ComplexRangeKind

diff  --git a/clang/test/CIR/CodeGen/complex-plus-minus.cpp 
b/clang/test/CIR/CodeGen/complex-plus-minus.cpp
index de3c1e127f0e1..d432d3ee96942 100644
--- a/clang/test/CIR/CodeGen/complex-plus-minus.cpp
+++ b/clang/test/CIR/CodeGen/complex-plus-minus.cpp
@@ -315,3 +315,75 @@ void foo6() {
 // 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 scalar_complex_minus() {
+  double real = 0.5;
+  double imag = -0.25;
+  double _Complex a = __builtin_complex(real, imag);
+  double _Complex b = real - a;
+}
+
+// CIR: %[[REAL_ADDR:.*]] = cir.alloca "real" {{.*}} init : 
!cir.ptr<!cir.double>
+// CIR: %[[IMAG_ADDR:.*]] = cir.alloca "imag" {{.*}} init : 
!cir.ptr<!cir.double>
+// CIR: %[[A_ADDR:.*]] = cir.alloca "a" {{.*}} init : 
!cir.ptr<!cir.complex<!cir.double>>
+// CIR: %[[B_ADDR:.*]] = cir.alloca "b" {{.*}} init : 
!cir.ptr<!cir.complex<!cir.double>>
+// CIR: %[[CONST_5F:.*]] = cir.const #cir.fp<5.000000e-01> : !cir.double
+// CIR: cir.store {{.*}} %[[CONST_5F]], %[[REAL_ADDR]] : !cir.double, 
!cir.ptr<!cir.double>
+// CIR: %[[CONST_N2_5F:.*]] = cir.const #cir.fp<-2.500000e-01> : !cir.double
+// CIR: cir.store {{.*}} %[[CONST_N2_5F]], %[[IMAG_ADDR]] : !cir.double, 
!cir.ptr<!cir.double>
+// CIR: %[[TMP_REAL:.*]] = cir.load {{.*}} %[[REAL_ADDR]] : 
!cir.ptr<!cir.double>, !cir.double
+// CIR: %[[TMP_IMAG:.*]] = cir.load {{.*}} %[[IMAG_ADDR]] : 
!cir.ptr<!cir.double>, !cir.double
+// CIR: %[[COMPLEX_A:.*]] = cir.complex.create %[[TMP_REAL]], %[[TMP_IMAG]] : 
!cir.double -> !cir.complex<!cir.double>
+// CIR: cir.store {{.*}} %[[COMPLEX_A]], %[[A_ADDR]] : 
!cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>
+// CIR: %[[TMP_REAL:.*]] = cir.load {{.*}} %[[REAL_ADDR]] : 
!cir.ptr<!cir.double>, !cir.double
+// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : 
!cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double>
+// CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : 
!cir.complex<!cir.double> -> !cir.double
+// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : 
!cir.complex<!cir.double> -> !cir.double
+// CIR: %[[RESULT_REAL:.*]] = cir.fsub %[[TMP_REAL]], %[[A_REAL]] : !cir.double
+// CIR: %[[RESULT_IMAG:.*]] = cir.fneg %[[A_IMAG]] : !cir.double
+// CIR: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] 
: !cir.double -> !cir.complex<!cir.double>
+// CIR: cir.store {{.*}} %[[RESULT]], %[[B_ADDR]] : !cir.complex<!cir.double>, 
!cir.ptr<!cir.complex<!cir.double>>
+
+// LLVM: %[[REAL_ADDR:.*]] = alloca double, i64 1, align 8
+// LLVM: %[[IMAG_ADDR:.*]] = alloca double, i64 1, align 8
+// LLVM: %[[A_ADDR:.*]] = alloca { double, double }, i64 1, align 8
+// LLVM: %[[B_ADDR:.*]] = alloca { double, double }, i64 1, align 8
+// LLVM: store double 5.000000e-01, ptr %[[REAL_ADDR]], align 8
+// LLVM: store double -2.500000e-01, ptr %[[IMAG_ADDR]], align 8
+// LLVM: %[[TMP_REAL:.*]] = load double, ptr %[[REAL_ADDR]], align 8
+// LLVM: %[[TMP_IMAG:.*]] = load double, ptr %[[IMAG_ADDR]], align 8
+// LLVM: %[[TMP_COMPLEX_A:.*]] = insertvalue { double, double } {{.*}}, double 
%[[TMP_REAL]], 0
+// LLVM: %[[COMPLEX_A:.*]] = insertvalue { double, double } 
%[[TMP_COMPLEX_A]], double %[[TMP_IMAG]], 1
+// LLVM: store { double, double } %[[COMPLEX_A]], ptr %[[A_ADDR]], align 8
+// LLVM: %[[TMP_REAL:.*]] = load double, ptr %[[REAL_ADDR]], align 8
+// LLVM: %[[TMP_A:.*]] = load { double, double }, ptr %[[A_ADDR]], align 8
+// LLVM: %[[A_REAL:.*]] = extractvalue { double, double } %[[TMP_A]], 0
+// LLVM: %[[A_IMAG:.*]] = extractvalue { double, double } %[[TMP_A]], 1
+// LLVM: %[[RESULT_REAL:.*]] = fsub double %[[TMP_REAL]], %[[A_REAL]]
+// LLVM: %[[RESULT_IMAG:.*]] = fneg double %[[A_IMAG]]
+// LLVM: %[[TMP_RESULT:.*]] = insertvalue { double, double } {{.*}}, double 
%[[RESULT_REAL]], 0
+// LLVM: %[[RESULT:.*]] = insertvalue { double, double } %[[TMP_RESULT]], 
double %[[RESULT_IMAG]], 1
+// LLVM: store { double, double } %[[RESULT]], ptr %[[B_ADDR]], align 8
+
+// OGCG: %[[REAL_ADDR:.*]] = alloca double, align 8
+// OGCG: %[[IMAG_ADDR:.*]] = alloca double, align 8
+// OGCG: %[[A_ADDR:.*]] = alloca { double, double }, align 8
+// OGCG: %[[B_ADDR:.*]] = alloca { double, double }, align 8
+// OGCG: store double 5.000000e-01, ptr %[[REAL_ADDR]], align 8
+// OGCG: store double -2.500000e-01, ptr %[[IMAG_ADDR]], align 8
+// OGCG: %[[TMP_REAL:.*]] = load double, ptr %[[REAL_ADDR]], align 8
+// OGCG: %[[TMP_IMAG:.*]] = load double, ptr %[[IMAG_ADDR]], align 8
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, 
ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, 
ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: store double %[[TMP_REAL]], ptr %[[A_REAL_PTR]], align 8
+// OGCG: store double %[[TMP_IMAG]], ptr %[[A_IMAG_PTR]], align 8
+// OGCG: %[[TMP_REAL:.*]] = load double, ptr %[[REAL_ADDR]], align 8
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, 
ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_REAL:.*]] = load double, ptr %[[A_REAL_PTR]], align 8
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, 
ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load double, ptr %[[A_IMAG_PTR]], align 8
+// OGCG: %[[RESULT_REAL:.*]] = fsub double %[[TMP_REAL]], %[[A_REAL]]
+// OGCG: %[[RESULT_IMAG:.*]] = fneg double %[[A_IMAG]]
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, 
ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, 
ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG: store double %[[RESULT_REAL]], ptr %[[B_REAL_PTR]], align 8
+// OGCG: store double %[[RESULT_IMAG]], ptr %[[B_IMAG_PTR]], align 8


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to