Author: Amr Hesham
Date: 2025-09-26T18:19:21+02:00
New Revision: 3aaa58fd903b26831f986140acbfdac4e07d4f12

URL: 
https://github.com/llvm/llvm-project/commit/3aaa58fd903b26831f986140acbfdac4e07d4f12
DIFF: 
https://github.com/llvm/llvm-project/commit/3aaa58fd903b26831f986140acbfdac4e07d4f12.diff

LOG: [Clang] Fix Codegen UO real/imag crash on scalar with type promotion 
(#160609)

Fixing codegen crash when compiling real/imag unary operators on scalar
with type promotion

Ref: #160583

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/CodeGen/CGExprScalar.cpp
    clang/test/CodeGen/complex.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9744c4f17610b..977396e249622 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -566,6 +566,7 @@ Crash and bug fixes
 - Fixed a crash in the static analyzer that when the expression in an
   ``[[assume(expr)]]`` attribute was enclosed in parentheses.  (#GH151529)
 - Fixed a crash when parsing ``#embed`` parameters with unmatched closing 
brackets. (#GH152829)
+- Fixed a crash when compiling ``__real__`` or ``__imag__`` unary operator on 
scalar value with type promotion. (#GH160583)
 
 Improvements
 ^^^^^^^^^^^^

diff  --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 4fa25c5d66669..f319b176513f8 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -3672,17 +3672,19 @@ Value *ScalarExprEmitter::VisitReal(const UnaryOperator 
*E,
     // If it's an l-value, load through the appropriate subobject l-value.
     // Note that we have to ask E because Op might be an l-value that
     // this won't work for, e.g. an Obj-C property.
-    if (E->isGLValue())  {
+    if (E->isGLValue()) {
       if (!PromotionType.isNull()) {
         CodeGenFunction::ComplexPairTy result = CGF.EmitComplexExpr(
             Op, /*IgnoreReal*/ IgnoreResultAssign, /*IgnoreImag*/ true);
-        if (result.first)
-          result.first = CGF.EmitPromotedValue(result, PromotionType).first;
-        return result.first;
-      } else {
-        return CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getExprLoc())
-            .getScalarVal();
+        PromotionType = PromotionType->isAnyComplexType()
+                            ? PromotionType
+                            : CGF.getContext().getComplexType(PromotionType);
+        return result.first ? CGF.EmitPromotedValue(result, 
PromotionType).first
+                            : result.first;
       }
+
+      return CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getExprLoc())
+          .getScalarVal();
     }
     // Otherwise, calculate and project.
     return CGF.EmitComplexExpr(Op, false, true).first;
@@ -3715,13 +3717,16 @@ Value *ScalarExprEmitter::VisitImag(const UnaryOperator 
*E,
       if (!PromotionType.isNull()) {
         CodeGenFunction::ComplexPairTy result = CGF.EmitComplexExpr(
             Op, /*IgnoreReal*/ true, /*IgnoreImag*/ IgnoreResultAssign);
-        if (result.second)
-          result.second = CGF.EmitPromotedValue(result, PromotionType).second;
-        return result.second;
-      } else {
-        return CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getExprLoc())
-            .getScalarVal();
+        PromotionType = PromotionType->isAnyComplexType()
+                            ? PromotionType
+                            : CGF.getContext().getComplexType(PromotionType);
+        return result.second
+                   ? CGF.EmitPromotedValue(result, PromotionType).second
+                   : result.second;
       }
+
+      return CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getExprLoc())
+          .getScalarVal();
     }
     // Otherwise, calculate and project.
     return CGF.EmitComplexExpr(Op, true, false).second;

diff  --git a/clang/test/CodeGen/complex.c b/clang/test/CodeGen/complex.c
index 6233529a18f8b..91fc9dda72f72 100644
--- a/clang/test/CodeGen/complex.c
+++ b/clang/test/CodeGen/complex.c
@@ -1,5 +1,81 @@
-// RUN: %clang_cc1 -emit-llvm-only %s
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 6
+// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-unknown-unknown -o - | 
FileCheck %s
 
+// CHECK-LABEL: define dso_local i32 @main(
+// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*]]:
+// CHECK-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[A:%.*]] = alloca { double, double }, align 8
+// CHECK-NEXT:    [[B:%.*]] = alloca { double, double }, align 8
+// CHECK-NEXT:    store i32 0, ptr [[RETVAL]], align 4
+// CHECK-NEXT:    [[A_REALP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[A]], i32 0, i32 0
+// CHECK-NEXT:    [[A_IMAGP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[A]], i32 0, i32 1
+// CHECK-NEXT:    store double 5.000000e+00, ptr [[A_REALP]], align 8
+// CHECK-NEXT:    store double 0.000000e+00, ptr [[A_IMAGP]], align 8
+// CHECK-NEXT:    [[B_REALP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[B]], i32 0, i32 0
+// CHECK-NEXT:    [[B_IMAGP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[B]], i32 0, i32 1
+// CHECK-NEXT:    store double 4.200000e+01, ptr [[B_REALP]], align 8
+// CHECK-NEXT:    store double 0.000000e+00, ptr [[B_IMAGP]], align 8
+// CHECK-NEXT:    [[A_REALP1:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[A]], i32 0, i32 0
+// CHECK-NEXT:    [[A_REAL:%.*]] = load double, ptr [[A_REALP1]], align 8
+// CHECK-NEXT:    [[A_IMAGP2:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[A]], i32 0, i32 1
+// CHECK-NEXT:    [[A_IMAG:%.*]] = load double, ptr [[A_IMAGP2]], align 8
+// CHECK-NEXT:    [[B_REALP3:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[B]], i32 0, i32 0
+// CHECK-NEXT:    [[B_REAL:%.*]] = load double, ptr [[B_REALP3]], align 8
+// CHECK-NEXT:    [[B_IMAGP4:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[B]], i32 0, i32 1
+// CHECK-NEXT:    [[B_IMAG:%.*]] = load double, ptr [[B_IMAGP4]], align 8
+// CHECK-NEXT:    [[MUL_AC:%.*]] = fmul double [[A_REAL]], [[B_REAL]]
+// CHECK-NEXT:    [[MUL_BD:%.*]] = fmul double [[A_IMAG]], [[B_IMAG]]
+// CHECK-NEXT:    [[MUL_AD:%.*]] = fmul double [[A_REAL]], [[B_IMAG]]
+// CHECK-NEXT:    [[MUL_BC:%.*]] = fmul double [[A_IMAG]], [[B_REAL]]
+// CHECK-NEXT:    [[MUL_R:%.*]] = fsub double [[MUL_AC]], [[MUL_BD]]
+// CHECK-NEXT:    [[MUL_I:%.*]] = fadd double [[MUL_AD]], [[MUL_BC]]
+// CHECK-NEXT:    [[ISNAN_CMP:%.*]] = fcmp uno double [[MUL_R]], [[MUL_R]]
+// CHECK-NEXT:    br i1 [[ISNAN_CMP]], label %[[COMPLEX_MUL_IMAG_NAN:.*]], 
label %[[COMPLEX_MUL_CONT:.*]], !prof [[PROF2:![0-9]+]]
+// CHECK:       [[COMPLEX_MUL_IMAG_NAN]]:
+// CHECK-NEXT:    [[ISNAN_CMP5:%.*]] = fcmp uno double [[MUL_I]], [[MUL_I]]
+// CHECK-NEXT:    br i1 [[ISNAN_CMP5]], label %[[COMPLEX_MUL_LIBCALL:.*]], 
label %[[COMPLEX_MUL_CONT]], !prof [[PROF2]]
+// CHECK:       [[COMPLEX_MUL_LIBCALL]]:
+// CHECK-NEXT:    [[CALL:%.*]] = call { double, double } @__muldc3(double 
noundef [[A_REAL]], double noundef [[A_IMAG]], double noundef [[B_REAL]], 
double noundef [[B_IMAG]]) #[[ATTR4:[0-9]+]]
+// CHECK-NEXT:    [[TMP0:%.*]] = extractvalue { double, double } [[CALL]], 0
+// CHECK-NEXT:    [[TMP1:%.*]] = extractvalue { double, double } [[CALL]], 1
+// CHECK-NEXT:    br label %[[COMPLEX_MUL_CONT]]
+// CHECK:       [[COMPLEX_MUL_CONT]]:
+// CHECK-NEXT:    [[REAL_MUL_PHI:%.*]] = phi double [ [[MUL_R]], %[[ENTRY]] ], 
[ [[MUL_R]], %[[COMPLEX_MUL_IMAG_NAN]] ], [ [[TMP0]], %[[COMPLEX_MUL_LIBCALL]] ]
+// CHECK-NEXT:    [[IMAG_MUL_PHI:%.*]] = phi double [ [[MUL_I]], %[[ENTRY]] ], 
[ [[MUL_I]], %[[COMPLEX_MUL_IMAG_NAN]] ], [ [[TMP1]], %[[COMPLEX_MUL_LIBCALL]] ]
+// CHECK-NEXT:    [[B_REALP6:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[B]], i32 0, i32 0
+// CHECK-NEXT:    [[B_REAL7:%.*]] = load double, ptr [[B_REALP6]], align 8
+// CHECK-NEXT:    [[B_IMAGP8:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[B]], i32 0, i32 1
+// CHECK-NEXT:    [[B_IMAG9:%.*]] = load double, ptr [[B_IMAGP8]], align 8
+// CHECK-NEXT:    [[A_REALP10:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[A]], i32 0, i32 0
+// CHECK-NEXT:    [[A_REAL11:%.*]] = load double, ptr [[A_REALP10]], align 8
+// CHECK-NEXT:    [[A_IMAGP12:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[A]], i32 0, i32 1
+// CHECK-NEXT:    [[A_IMAG13:%.*]] = load double, ptr [[A_IMAGP12]], align 8
+// CHECK-NEXT:    [[MUL_AC14:%.*]] = fmul double [[B_REAL7]], [[A_REAL11]]
+// CHECK-NEXT:    [[MUL_BD15:%.*]] = fmul double [[B_IMAG9]], [[A_IMAG13]]
+// CHECK-NEXT:    [[MUL_AD16:%.*]] = fmul double [[B_REAL7]], [[A_IMAG13]]
+// CHECK-NEXT:    [[MUL_BC17:%.*]] = fmul double [[B_IMAG9]], [[A_REAL11]]
+// CHECK-NEXT:    [[MUL_R18:%.*]] = fsub double [[MUL_AC14]], [[MUL_BD15]]
+// CHECK-NEXT:    [[MUL_I19:%.*]] = fadd double [[MUL_AD16]], [[MUL_BC17]]
+// CHECK-NEXT:    [[ISNAN_CMP20:%.*]] = fcmp uno double [[MUL_R18]], 
[[MUL_R18]]
+// CHECK-NEXT:    br i1 [[ISNAN_CMP20]], label %[[COMPLEX_MUL_IMAG_NAN21:.*]], 
label %[[COMPLEX_MUL_CONT25:.*]], !prof [[PROF2]]
+// CHECK:       [[COMPLEX_MUL_IMAG_NAN21]]:
+// CHECK-NEXT:    [[ISNAN_CMP22:%.*]] = fcmp uno double [[MUL_I19]], 
[[MUL_I19]]
+// CHECK-NEXT:    br i1 [[ISNAN_CMP22]], label %[[COMPLEX_MUL_LIBCALL23:.*]], 
label %[[COMPLEX_MUL_CONT25]], !prof [[PROF2]]
+// CHECK:       [[COMPLEX_MUL_LIBCALL23]]:
+// CHECK-NEXT:    [[CALL24:%.*]] = call { double, double } @__muldc3(double 
noundef [[B_REAL7]], double noundef [[B_IMAG9]], double noundef [[A_REAL11]], 
double noundef [[A_IMAG13]]) #[[ATTR4]]
+// CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { double, double } [[CALL24]], 0
+// CHECK-NEXT:    [[TMP3:%.*]] = extractvalue { double, double } [[CALL24]], 1
+// CHECK-NEXT:    br label %[[COMPLEX_MUL_CONT25]]
+// CHECK:       [[COMPLEX_MUL_CONT25]]:
+// CHECK-NEXT:    [[REAL_MUL_PHI26:%.*]] = phi double [ [[MUL_R18]], 
%[[COMPLEX_MUL_CONT]] ], [ [[MUL_R18]], %[[COMPLEX_MUL_IMAG_NAN21]] ], [ 
[[TMP2]], %[[COMPLEX_MUL_LIBCALL23]] ]
+// CHECK-NEXT:    [[IMAG_MUL_PHI27:%.*]] = phi double [ [[MUL_I19]], 
%[[COMPLEX_MUL_CONT]] ], [ [[MUL_I19]], %[[COMPLEX_MUL_IMAG_NAN21]] ], [ 
[[TMP3]], %[[COMPLEX_MUL_LIBCALL23]] ]
+// CHECK-NEXT:    [[CMP_R:%.*]] = fcmp une double [[REAL_MUL_PHI]], 
[[REAL_MUL_PHI26]]
+// CHECK-NEXT:    [[CMP_I:%.*]] = fcmp une double [[IMAG_MUL_PHI]], 
[[IMAG_MUL_PHI27]]
+// CHECK-NEXT:    [[OR_RI:%.*]] = or i1 [[CMP_R]], [[CMP_I]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[OR_RI]] to i32
+// CHECK-NEXT:    ret i32 [[CONV]]
+//
 int main(void)
 {
   double _Complex a = 5;
@@ -12,6 +88,36 @@ _Complex double bar(int);
 void test(_Complex double*);
 void takecomplex(_Complex double);
 
+// CHECK-LABEL: define dso_local void @test2(
+// CHECK-SAME: i32 noundef [[C:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[C_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[X:%.*]] = alloca { double, double }, align 8
+// CHECK-NEXT:    [[COERCE:%.*]] = alloca { double, double }, align 8
+// CHECK-NEXT:    store i32 [[C]], ptr [[C_ADDR]], align 4
+// CHECK-NEXT:    [[CALL:%.*]] = call { double, double } @bar(i32 noundef 1)
+// CHECK-NEXT:    [[TMP0:%.*]] = extractvalue { double, double } [[CALL]], 0
+// CHECK-NEXT:    [[TMP1:%.*]] = extractvalue { double, double } [[CALL]], 1
+// CHECK-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[X]], i32 0, i32 0
+// CHECK-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[X]], i32 0, i32 1
+// CHECK-NEXT:    store double [[TMP0]], ptr [[X_REALP]], align 8
+// CHECK-NEXT:    store double [[TMP1]], ptr [[X_IMAGP]], align 8
+// CHECK-NEXT:    call void @test(ptr noundef [[X]])
+// CHECK-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[X]], i32 0, i32 0
+// CHECK-NEXT:    [[X_REAL:%.*]] = load double, ptr [[X_REALP1]], align 8
+// CHECK-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[X]], i32 0, i32 1
+// CHECK-NEXT:    [[X_IMAG:%.*]] = load double, ptr [[X_IMAGP2]], align 8
+// CHECK-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[COERCE]], i32 0, i32 0
+// CHECK-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[COERCE]], i32 0, i32 1
+// CHECK-NEXT:    store double [[X_REAL]], ptr [[COERCE_REALP]], align 8
+// CHECK-NEXT:    store double [[X_IMAG]], ptr [[COERCE_IMAGP]], align 8
+// CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds nuw { double, double 
}, ptr [[COERCE]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP3:%.*]] = load double, ptr [[TMP2]], align 8
+// CHECK-NEXT:    [[TMP4:%.*]] = getelementptr inbounds nuw { double, double 
}, ptr [[COERCE]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP5:%.*]] = load double, ptr [[TMP4]], align 8
+// CHECK-NEXT:    call void @takecomplex(double noundef [[TMP3]], double 
noundef [[TMP5]])
+// CHECK-NEXT:    ret void
+//
 void test2(int c) {
   _Complex double X;
   X = bar(1);
@@ -23,6 +129,104 @@ _Complex double g1, g2;
 _Complex float cf;
 double D;
 
+// CHECK-LABEL: define dso_local void @test3(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*]]:
+// CHECK-NEXT:    [[GR:%.*]] = alloca double, align 8
+// CHECK-NEXT:    [[G1_REAL:%.*]] = load double, ptr @g1, align 8
+// CHECK-NEXT:    [[G1_IMAG:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[G2_REAL:%.*]] = load double, ptr @g2, align 8
+// CHECK-NEXT:    [[G2_IMAG:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g2, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[ADD_R:%.*]] = fadd double [[G1_REAL]], [[G2_REAL]]
+// CHECK-NEXT:    [[ADD_I:%.*]] = fadd double [[G1_IMAG]], [[G2_IMAG]]
+// CHECK-NEXT:    store double [[ADD_R]], ptr @g1, align 8
+// CHECK-NEXT:    store double [[ADD_I]], ptr getelementptr inbounds nuw ({ 
double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[G1_REAL1:%.*]] = load double, ptr @g1, align 8
+// CHECK-NEXT:    [[G1_IMAG2:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[G2_REAL3:%.*]] = load double, ptr @g2, align 8
+// CHECK-NEXT:    [[G2_IMAG4:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g2, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[SUB_R:%.*]] = fsub double [[G1_REAL1]], [[G2_REAL3]]
+// CHECK-NEXT:    [[SUB_I:%.*]] = fsub double [[G1_IMAG2]], [[G2_IMAG4]]
+// CHECK-NEXT:    store double [[SUB_R]], ptr @g1, align 8
+// CHECK-NEXT:    store double [[SUB_I]], ptr getelementptr inbounds nuw ({ 
double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[G1_REAL5:%.*]] = load double, ptr @g1, align 8
+// CHECK-NEXT:    [[G1_IMAG6:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[G2_REAL7:%.*]] = load double, ptr @g2, align 8
+// CHECK-NEXT:    [[G2_IMAG8:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g2, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[MUL_AC:%.*]] = fmul double [[G1_REAL5]], [[G2_REAL7]]
+// CHECK-NEXT:    [[MUL_BD:%.*]] = fmul double [[G1_IMAG6]], [[G2_IMAG8]]
+// CHECK-NEXT:    [[MUL_AD:%.*]] = fmul double [[G1_REAL5]], [[G2_IMAG8]]
+// CHECK-NEXT:    [[MUL_BC:%.*]] = fmul double [[G1_IMAG6]], [[G2_REAL7]]
+// CHECK-NEXT:    [[MUL_R:%.*]] = fsub double [[MUL_AC]], [[MUL_BD]]
+// CHECK-NEXT:    [[MUL_I:%.*]] = fadd double [[MUL_AD]], [[MUL_BC]]
+// CHECK-NEXT:    [[ISNAN_CMP:%.*]] = fcmp uno double [[MUL_R]], [[MUL_R]]
+// CHECK-NEXT:    br i1 [[ISNAN_CMP]], label %[[COMPLEX_MUL_IMAG_NAN:.*]], 
label %[[COMPLEX_MUL_CONT:.*]], !prof [[PROF2]]
+// CHECK:       [[COMPLEX_MUL_IMAG_NAN]]:
+// CHECK-NEXT:    [[ISNAN_CMP9:%.*]] = fcmp uno double [[MUL_I]], [[MUL_I]]
+// CHECK-NEXT:    br i1 [[ISNAN_CMP9]], label %[[COMPLEX_MUL_LIBCALL:.*]], 
label %[[COMPLEX_MUL_CONT]], !prof [[PROF2]]
+// CHECK:       [[COMPLEX_MUL_LIBCALL]]:
+// CHECK-NEXT:    [[CALL:%.*]] = call { double, double } @__muldc3(double 
noundef [[G1_REAL5]], double noundef [[G1_IMAG6]], double noundef [[G2_REAL7]], 
double noundef [[G2_IMAG8]]) #[[ATTR4]]
+// CHECK-NEXT:    [[TMP0:%.*]] = extractvalue { double, double } [[CALL]], 0
+// CHECK-NEXT:    [[TMP1:%.*]] = extractvalue { double, double } [[CALL]], 1
+// CHECK-NEXT:    br label %[[COMPLEX_MUL_CONT]]
+// CHECK:       [[COMPLEX_MUL_CONT]]:
+// CHECK-NEXT:    [[REAL_MUL_PHI:%.*]] = phi double [ [[MUL_R]], %[[ENTRY]] ], 
[ [[MUL_R]], %[[COMPLEX_MUL_IMAG_NAN]] ], [ [[TMP0]], %[[COMPLEX_MUL_LIBCALL]] ]
+// CHECK-NEXT:    [[IMAG_MUL_PHI:%.*]] = phi double [ [[MUL_I]], %[[ENTRY]] ], 
[ [[MUL_I]], %[[COMPLEX_MUL_IMAG_NAN]] ], [ [[TMP1]], %[[COMPLEX_MUL_LIBCALL]] ]
+// CHECK-NEXT:    store double [[REAL_MUL_PHI]], ptr @g1, align 8
+// CHECK-NEXT:    store double [[IMAG_MUL_PHI]], ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[G1_REAL10:%.*]] = load double, ptr @g1, align 8
+// CHECK-NEXT:    [[G1_IMAG11:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[CONJ_I:%.*]] = fneg double [[G1_IMAG11]]
+// CHECK-NEXT:    [[NEG_R:%.*]] = fneg double [[G1_REAL10]]
+// CHECK-NEXT:    [[NEG_I:%.*]] = fneg double [[CONJ_I]]
+// CHECK-NEXT:    store double [[NEG_R]], ptr @g1, align 8
+// CHECK-NEXT:    store double [[NEG_I]], ptr getelementptr inbounds nuw ({ 
double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[TMP2:%.*]] = load double, ptr @g1, align 8
+// CHECK-NEXT:    store double [[TMP2]], ptr [[GR]], align 8
+// CHECK-NEXT:    [[TMP3:%.*]] = load double, ptr @D, align 8
+// CHECK-NEXT:    [[CF_REAL:%.*]] = load float, ptr @cf, align 4
+// CHECK-NEXT:    [[CF_IMAG:%.*]] = load float, ptr getelementptr inbounds nuw 
({ float, float }, ptr @cf, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CONV:%.*]] = fpext float [[CF_REAL]] to double
+// CHECK-NEXT:    [[CONV12:%.*]] = fpext float [[CF_IMAG]] to double
+// CHECK-NEXT:    [[ADD_R13:%.*]] = fadd double [[CONV]], [[TMP3]]
+// CHECK-NEXT:    [[CONV14:%.*]] = fptrunc double [[ADD_R13]] to float
+// CHECK-NEXT:    [[CONV15:%.*]] = fptrunc double [[CONV12]] to float
+// CHECK-NEXT:    store float [[CONV14]], ptr @cf, align 4
+// CHECK-NEXT:    store float [[CONV15]], ptr getelementptr inbounds nuw ({ 
float, float }, ptr @cf, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CF_REAL16:%.*]] = load float, ptr @cf, align 4
+// CHECK-NEXT:    [[CF_IMAG17:%.*]] = load float, ptr getelementptr inbounds 
nuw ({ float, float }, ptr @cf, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CONV18:%.*]] = fpext float [[CF_REAL16]] to double
+// CHECK-NEXT:    [[CONV19:%.*]] = fpext float [[CF_IMAG17]] to double
+// CHECK-NEXT:    [[TMP4:%.*]] = load double, ptr @D, align 8
+// CHECK-NEXT:    [[ADD_R20:%.*]] = fadd double [[TMP4]], [[CONV18]]
+// CHECK-NEXT:    store double [[ADD_R20]], ptr @D, align 8
+// CHECK-NEXT:    [[G1_REAL21:%.*]] = load double, ptr @g1, align 8
+// CHECK-NEXT:    [[G1_IMAG22:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[CF_REAL23:%.*]] = load float, ptr @cf, align 4
+// CHECK-NEXT:    [[CF_IMAG24:%.*]] = load float, ptr getelementptr inbounds 
nuw ({ float, float }, ptr @cf, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CONV25:%.*]] = fpext float [[CF_REAL23]] to double
+// CHECK-NEXT:    [[CONV26:%.*]] = fpext float [[CF_IMAG24]] to double
+// CHECK-NEXT:    [[CALL27:%.*]] = call { double, double } @__divdc3(double 
noundef [[CONV25]], double noundef [[CONV26]], double noundef [[G1_REAL21]], 
double noundef [[G1_IMAG22]]) #[[ATTR4]]
+// CHECK-NEXT:    [[TMP5:%.*]] = extractvalue { double, double } [[CALL27]], 0
+// CHECK-NEXT:    [[TMP6:%.*]] = extractvalue { double, double } [[CALL27]], 1
+// CHECK-NEXT:    [[CONV28:%.*]] = fptrunc double [[TMP5]] to float
+// CHECK-NEXT:    [[CONV29:%.*]] = fptrunc double [[TMP6]] to float
+// CHECK-NEXT:    store float [[CONV28]], ptr @cf, align 4
+// CHECK-NEXT:    store float [[CONV29]], ptr getelementptr inbounds nuw ({ 
float, float }, ptr @cf, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[G1_REAL30:%.*]] = load double, ptr @g1, align 8
+// CHECK-NEXT:    [[G1_IMAG31:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[TMP7:%.*]] = load double, ptr @D, align 8
+// CHECK-NEXT:    [[ADD_R32:%.*]] = fadd double [[G1_REAL30]], [[TMP7]]
+// CHECK-NEXT:    store double [[ADD_R32]], ptr @g1, align 8
+// CHECK-NEXT:    store double [[G1_IMAG31]], ptr getelementptr inbounds nuw 
({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[TMP8:%.*]] = load double, ptr @D, align 8
+// CHECK-NEXT:    [[G1_REAL33:%.*]] = load double, ptr @g1, align 8
+// CHECK-NEXT:    [[G1_IMAG34:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[ADD_R35:%.*]] = fadd double [[TMP8]], [[G1_REAL33]]
+// CHECK-NEXT:    store double [[ADD_R35]], ptr @g1, align 8
+// CHECK-NEXT:    store double [[G1_IMAG34]], ptr getelementptr inbounds nuw 
({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    ret void
+//
 void test3(void) {
   g1 = g1 + g2;
   g1 = g1 - g2;
@@ -41,6 +245,101 @@ void test3(void) {
 __complex__ int ci1, ci2;
 __complex__ short cs;
 int i;
+// CHECK-LABEL: define dso_local void @test3int(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[CI1_REAL:%.*]] = load i32, ptr @ci1, align 4
+// CHECK-NEXT:    [[CI1_IMAG:%.*]] = load i32, ptr getelementptr inbounds nuw 
({ i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CI2_REAL:%.*]] = load i32, ptr @ci2, align 4
+// CHECK-NEXT:    [[CI2_IMAG:%.*]] = load i32, ptr getelementptr inbounds nuw 
({ i32, i32 }, ptr @ci2, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[ADD_R:%.*]] = add i32 [[CI1_REAL]], [[CI2_REAL]]
+// CHECK-NEXT:    [[ADD_I:%.*]] = add i32 [[CI1_IMAG]], [[CI2_IMAG]]
+// CHECK-NEXT:    store i32 [[ADD_R]], ptr @ci1, align 4
+// CHECK-NEXT:    store i32 [[ADD_I]], ptr getelementptr inbounds nuw ({ i32, 
i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CI1_REAL1:%.*]] = load i32, ptr @ci1, align 4
+// CHECK-NEXT:    [[CI1_IMAG2:%.*]] = load i32, ptr getelementptr inbounds nuw 
({ i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CI2_REAL3:%.*]] = load i32, ptr @ci2, align 4
+// CHECK-NEXT:    [[CI2_IMAG4:%.*]] = load i32, ptr getelementptr inbounds nuw 
({ i32, i32 }, ptr @ci2, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[SUB_R:%.*]] = sub i32 [[CI1_REAL1]], [[CI2_REAL3]]
+// CHECK-NEXT:    [[SUB_I:%.*]] = sub i32 [[CI1_IMAG2]], [[CI2_IMAG4]]
+// CHECK-NEXT:    store i32 [[SUB_R]], ptr @ci1, align 4
+// CHECK-NEXT:    store i32 [[SUB_I]], ptr getelementptr inbounds nuw ({ i32, 
i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CI1_REAL5:%.*]] = load i32, ptr @ci1, align 4
+// CHECK-NEXT:    [[CI1_IMAG6:%.*]] = load i32, ptr getelementptr inbounds nuw 
({ i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CI2_REAL7:%.*]] = load i32, ptr @ci2, align 4
+// CHECK-NEXT:    [[CI2_IMAG8:%.*]] = load i32, ptr getelementptr inbounds nuw 
({ i32, i32 }, ptr @ci2, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[MUL_RL:%.*]] = mul i32 [[CI1_REAL5]], [[CI2_REAL7]]
+// CHECK-NEXT:    [[MUL_RR:%.*]] = mul i32 [[CI1_IMAG6]], [[CI2_IMAG8]]
+// CHECK-NEXT:    [[MUL_R:%.*]] = sub i32 [[MUL_RL]], [[MUL_RR]]
+// CHECK-NEXT:    [[MUL_IL:%.*]] = mul i32 [[CI1_IMAG6]], [[CI2_REAL7]]
+// CHECK-NEXT:    [[MUL_IR:%.*]] = mul i32 [[CI1_REAL5]], [[CI2_IMAG8]]
+// CHECK-NEXT:    [[MUL_I:%.*]] = add i32 [[MUL_IL]], [[MUL_IR]]
+// CHECK-NEXT:    store i32 [[MUL_R]], ptr @ci1, align 4
+// CHECK-NEXT:    store i32 [[MUL_I]], ptr getelementptr inbounds nuw ({ i32, 
i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CI1_REAL9:%.*]] = load i32, ptr @ci1, align 4
+// CHECK-NEXT:    [[CI1_IMAG10:%.*]] = load i32, ptr getelementptr inbounds 
nuw ({ i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CONJ_I:%.*]] = sub i32 0, [[CI1_IMAG10]]
+// CHECK-NEXT:    [[NEG_R:%.*]] = sub i32 0, [[CI1_REAL9]]
+// CHECK-NEXT:    [[NEG_I:%.*]] = sub i32 0, [[CONJ_I]]
+// CHECK-NEXT:    store i32 [[NEG_R]], ptr @ci1, align 4
+// CHECK-NEXT:    store i32 [[NEG_I]], ptr getelementptr inbounds nuw ({ i32, 
i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @ci1, align 4
+// CHECK-NEXT:    store i32 [[TMP0]], ptr @i, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr @i, align 4
+// CHECK-NEXT:    [[CS_REAL:%.*]] = load i16, ptr @cs, align 2
+// CHECK-NEXT:    [[CS_IMAG:%.*]] = load i16, ptr getelementptr inbounds nuw 
({ i16, i16 }, ptr @cs, i32 0, i32 1), align 2
+// CHECK-NEXT:    [[CONV:%.*]] = sext i16 [[CS_REAL]] to i32
+// CHECK-NEXT:    [[CONV11:%.*]] = sext i16 [[CS_IMAG]] to i32
+// CHECK-NEXT:    [[ADD_R12:%.*]] = add i32 [[CONV]], [[TMP1]]
+// CHECK-NEXT:    [[ADD_I13:%.*]] = add i32 [[CONV11]], 0
+// CHECK-NEXT:    [[CONV14:%.*]] = trunc i32 [[ADD_R12]] to i16
+// CHECK-NEXT:    [[CONV15:%.*]] = trunc i32 [[ADD_I13]] to i16
+// CHECK-NEXT:    store i16 [[CONV14]], ptr @cs, align 2
+// CHECK-NEXT:    store i16 [[CONV15]], ptr getelementptr inbounds nuw ({ i16, 
i16 }, ptr @cs, i32 0, i32 1), align 2
+// CHECK-NEXT:    [[CF_REAL:%.*]] = load float, ptr @cf, align 4
+// CHECK-NEXT:    [[CF_IMAG:%.*]] = load float, ptr getelementptr inbounds nuw 
({ float, float }, ptr @cf, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CONV16:%.*]] = fpext float [[CF_REAL]] to double
+// CHECK-NEXT:    [[CONV17:%.*]] = fpext float [[CF_IMAG]] to double
+// CHECK-NEXT:    [[TMP2:%.*]] = load double, ptr @D, align 8
+// CHECK-NEXT:    [[ADD_R18:%.*]] = fadd double [[TMP2]], [[CONV16]]
+// CHECK-NEXT:    store double [[ADD_R18]], ptr @D, align 8
+// CHECK-NEXT:    [[CI1_REAL19:%.*]] = load i32, ptr @ci1, align 4
+// CHECK-NEXT:    [[CI1_IMAG20:%.*]] = load i32, ptr getelementptr inbounds 
nuw ({ i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CS_REAL21:%.*]] = load i16, ptr @cs, align 2
+// CHECK-NEXT:    [[CS_IMAG22:%.*]] = load i16, ptr getelementptr inbounds nuw 
({ i16, i16 }, ptr @cs, i32 0, i32 1), align 2
+// CHECK-NEXT:    [[CONV23:%.*]] = sext i16 [[CS_REAL21]] to i32
+// CHECK-NEXT:    [[CONV24:%.*]] = sext i16 [[CS_IMAG22]] to i32
+// CHECK-NEXT:    [[TMP3:%.*]] = mul i32 [[CONV23]], [[CI1_REAL19]]
+// CHECK-NEXT:    [[TMP4:%.*]] = mul i32 [[CONV24]], [[CI1_IMAG20]]
+// CHECK-NEXT:    [[TMP5:%.*]] = add i32 [[TMP3]], [[TMP4]]
+// CHECK-NEXT:    [[TMP6:%.*]] = mul i32 [[CI1_REAL19]], [[CI1_REAL19]]
+// CHECK-NEXT:    [[TMP7:%.*]] = mul i32 [[CI1_IMAG20]], [[CI1_IMAG20]]
+// CHECK-NEXT:    [[TMP8:%.*]] = add i32 [[TMP6]], [[TMP7]]
+// CHECK-NEXT:    [[TMP9:%.*]] = mul i32 [[CONV24]], [[CI1_REAL19]]
+// CHECK-NEXT:    [[TMP10:%.*]] = mul i32 [[CONV23]], [[CI1_IMAG20]]
+// CHECK-NEXT:    [[TMP11:%.*]] = sub i32 [[TMP9]], [[TMP10]]
+// CHECK-NEXT:    [[TMP12:%.*]] = sdiv i32 [[TMP5]], [[TMP8]]
+// CHECK-NEXT:    [[TMP13:%.*]] = sdiv i32 [[TMP11]], [[TMP8]]
+// CHECK-NEXT:    [[CONV25:%.*]] = trunc i32 [[TMP12]] to i16
+// CHECK-NEXT:    [[CONV26:%.*]] = trunc i32 [[TMP13]] to i16
+// CHECK-NEXT:    store i16 [[CONV25]], ptr @cs, align 2
+// CHECK-NEXT:    store i16 [[CONV26]], ptr getelementptr inbounds nuw ({ i16, 
i16 }, ptr @cs, i32 0, i32 1), align 2
+// CHECK-NEXT:    [[CI1_REAL27:%.*]] = load i32, ptr @ci1, align 4
+// CHECK-NEXT:    [[CI1_IMAG28:%.*]] = load i32, ptr getelementptr inbounds 
nuw ({ i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[TMP14:%.*]] = load i32, ptr @i, align 4
+// CHECK-NEXT:    [[ADD_R29:%.*]] = add i32 [[CI1_REAL27]], [[TMP14]]
+// CHECK-NEXT:    [[ADD_I30:%.*]] = add i32 [[CI1_IMAG28]], 0
+// CHECK-NEXT:    store i32 [[ADD_R29]], ptr @ci1, align 4
+// CHECK-NEXT:    store i32 [[ADD_I30]], ptr getelementptr inbounds nuw ({ 
i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[TMP15:%.*]] = load i32, ptr @i, align 4
+// CHECK-NEXT:    [[CI1_REAL31:%.*]] = load i32, ptr @ci1, align 4
+// CHECK-NEXT:    [[CI1_IMAG32:%.*]] = load i32, ptr getelementptr inbounds 
nuw ({ i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[ADD_R33:%.*]] = add i32 [[TMP15]], [[CI1_REAL31]]
+// CHECK-NEXT:    [[ADD_I34:%.*]] = add i32 0, [[CI1_IMAG32]]
+// CHECK-NEXT:    store i32 [[ADD_R33]], ptr @ci1, align 4
+// CHECK-NEXT:    store i32 [[ADD_I34]], ptr getelementptr inbounds nuw ({ 
i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    ret void
+//
 void test3int(void) {
   ci1 = ci1 + ci2;
   ci1 = ci1 - ci2;
@@ -56,15 +355,37 @@ void test3int(void) {
   ci1 = i + ci1;
 }
 
+// CHECK-LABEL: define dso_local void @t1(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    store float 4.000000e+00, ptr @cf, align 4
+// CHECK-NEXT:    ret void
+//
 void t1(void) {
   (__real__ cf) = 4.0;
 }
 
+// CHECK-LABEL: define dso_local void @t2(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    store float 4.000000e+00, ptr getelementptr inbounds nuw ({ 
float, float }, ptr @cf, i32 0, i32 1), align 4
+// CHECK-NEXT:    ret void
+//
 void t2(void) {
   (__imag__ cf) = 4.0;
 }
 
 // PR1960
+// CHECK-LABEL: define dso_local void @t3(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[V:%.*]] = alloca { i64, i64 }, align 8
+// CHECK-NEXT:    [[V_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[V]], i32 0, i32 0
+// CHECK-NEXT:    [[V_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[V]], i32 0, i32 1
+// CHECK-NEXT:    store i64 2, ptr [[V_REALP]], align 8
+// CHECK-NEXT:    store i64 0, ptr [[V_IMAGP]], align 8
+// CHECK-NEXT:    ret void
+//
 void t3(void) {
   __complex__ long long v = 2;
 }
@@ -72,10 +393,72 @@ void t3(void) {
 // PR3131
 float _Complex t4(void);
 
+// CHECK-LABEL: define dso_local void @t5(
+// CHECK-SAME: ) #[[ATTR2:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[X:%.*]] = alloca { float, float }, align 4
+// CHECK-NEXT:    [[COERCE:%.*]] = alloca { float, float }, align 4
+// CHECK-NEXT:    [[CALL:%.*]] = call <2 x float> @t4()
+// CHECK-NEXT:    store <2 x float> [[CALL]], ptr [[COERCE]], align 4
+// CHECK-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { float, 
float }, ptr [[COERCE]], i32 0, i32 0
+// CHECK-NEXT:    [[COERCE_REAL:%.*]] = load float, ptr [[COERCE_REALP]], 
align 4
+// CHECK-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { float, 
float }, ptr [[COERCE]], i32 0, i32 1
+// CHECK-NEXT:    [[COERCE_IMAG:%.*]] = load float, ptr [[COERCE_IMAGP]], 
align 4
+// CHECK-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[X]], i32 0, i32 0
+// CHECK-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[X]], i32 0, i32 1
+// CHECK-NEXT:    store float [[COERCE_REAL]], ptr [[X_REALP]], align 4
+// CHECK-NEXT:    store float [[COERCE_IMAG]], ptr [[X_IMAGP]], align 4
+// CHECK-NEXT:    ret void
+//
 void t5(void) {
   float _Complex x = t4();
 }
 
+// CHECK-LABEL: define dso_local void @t6(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[G1_REAL:%.*]] = load double, ptr @g1, align 8
+// CHECK-NEXT:    [[G1_IMAG:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[INC:%.*]] = fadd double [[G1_REAL]], 1.000000e+00
+// CHECK-NEXT:    store double [[INC]], ptr @g1, align 8
+// CHECK-NEXT:    store double [[G1_IMAG]], ptr getelementptr inbounds nuw ({ 
double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[G1_REAL1:%.*]] = load double, ptr @g1, align 8
+// CHECK-NEXT:    [[G1_IMAG2:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[DEC:%.*]] = fadd double [[G1_REAL1]], -1.000000e+00
+// CHECK-NEXT:    store double [[DEC]], ptr @g1, align 8
+// CHECK-NEXT:    store double [[G1_IMAG2]], ptr getelementptr inbounds nuw ({ 
double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[G1_REAL3:%.*]] = load double, ptr @g1, align 8
+// CHECK-NEXT:    [[G1_IMAG4:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[INC5:%.*]] = fadd double [[G1_REAL3]], 1.000000e+00
+// CHECK-NEXT:    store double [[INC5]], ptr @g1, align 8
+// CHECK-NEXT:    store double [[G1_IMAG4]], ptr getelementptr inbounds nuw ({ 
double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[G1_REAL6:%.*]] = load double, ptr @g1, align 8
+// CHECK-NEXT:    [[G1_IMAG7:%.*]] = load double, ptr getelementptr inbounds 
nuw ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[DEC8:%.*]] = fadd double [[G1_REAL6]], -1.000000e+00
+// CHECK-NEXT:    store double [[DEC8]], ptr @g1, align 8
+// CHECK-NEXT:    store double [[G1_IMAG7]], ptr getelementptr inbounds nuw ({ 
double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    [[CI1_REAL:%.*]] = load i32, ptr @ci1, align 4
+// CHECK-NEXT:    [[CI1_IMAG:%.*]] = load i32, ptr getelementptr inbounds nuw 
({ i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[INC9:%.*]] = add i32 [[CI1_REAL]], 1
+// CHECK-NEXT:    store i32 [[INC9]], ptr @ci1, align 4
+// CHECK-NEXT:    store i32 [[CI1_IMAG]], ptr getelementptr inbounds nuw ({ 
i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CI1_REAL10:%.*]] = load i32, ptr @ci1, align 4
+// CHECK-NEXT:    [[CI1_IMAG11:%.*]] = load i32, ptr getelementptr inbounds 
nuw ({ i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[DEC12:%.*]] = add i32 [[CI1_REAL10]], -1
+// CHECK-NEXT:    store i32 [[DEC12]], ptr @ci1, align 4
+// CHECK-NEXT:    store i32 [[CI1_IMAG11]], ptr getelementptr inbounds nuw ({ 
i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CI1_REAL13:%.*]] = load i32, ptr @ci1, align 4
+// CHECK-NEXT:    [[CI1_IMAG14:%.*]] = load i32, ptr getelementptr inbounds 
nuw ({ i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[INC15:%.*]] = add i32 [[CI1_REAL13]], 1
+// CHECK-NEXT:    store i32 [[INC15]], ptr @ci1, align 4
+// CHECK-NEXT:    store i32 [[CI1_IMAG14]], ptr getelementptr inbounds nuw ({ 
i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[CI1_REAL16:%.*]] = load i32, ptr @ci1, align 4
+// CHECK-NEXT:    [[CI1_IMAG17:%.*]] = load i32, ptr getelementptr inbounds 
nuw ({ i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    [[DEC18:%.*]] = add i32 [[CI1_REAL16]], -1
+// CHECK-NEXT:    store i32 [[DEC18]], ptr @ci1, align 4
+// CHECK-NEXT:    store i32 [[CI1_IMAG17]], ptr getelementptr inbounds nuw ({ 
i32, i32 }, ptr @ci1, i32 0, i32 1), align 4
+// CHECK-NEXT:    ret void
+//
 void t6(void) {
   g1++;
   g1--;
@@ -87,18 +470,68 @@ void t6(void) {
   --ci1;
 }
 
+// CHECK-LABEL: define dso_local double @t7(
+// CHECK-SAME: double noundef [[C_COERCE0:%.*]], double noundef 
[[C_COERCE1:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[C:%.*]] = alloca { double, double }, align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw { double, double 
}, ptr [[C]], i32 0, i32 0
+// CHECK-NEXT:    store double [[C_COERCE0]], ptr [[TMP0]], align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { double, double 
}, ptr [[C]], i32 0, i32 1
+// CHECK-NEXT:    store double [[C_COERCE1]], ptr [[TMP1]], align 8
+// CHECK-NEXT:    [[C_REALP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[C]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load double, ptr [[C_REALP]], align 8
+// CHECK-NEXT:    [[TMP3:%.*]] = call double @llvm.fabs.f64(double [[TMP2]])
+// CHECK-NEXT:    ret double [[TMP3]]
+//
 double t7(double _Complex c) {
   return __builtin_fabs(__real__(c));
 }
 
+// CHECK-LABEL: define dso_local void @t8(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[X:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[DOTCOMPOUNDLITERAL:%.*]] = alloca { i32, i32 }, align 4
+// CHECK-NEXT:    [[DOTCOMPOUNDLITERAL_REALP:%.*]] = getelementptr inbounds 
nuw { i32, i32 }, ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 0
+// CHECK-NEXT:    [[DOTCOMPOUNDLITERAL_IMAGP:%.*]] = getelementptr inbounds 
nuw { i32, i32 }, ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 1
+// CHECK-NEXT:    store i32 1, ptr [[DOTCOMPOUNDLITERAL_REALP]], align 4
+// CHECK-NEXT:    store i32 0, ptr [[DOTCOMPOUNDLITERAL_IMAGP]], align 4
+// CHECK-NEXT:    store ptr [[DOTCOMPOUNDLITERAL]], ptr [[X]], align 8
+// CHECK-NEXT:    ret void
+//
 void t8(void) {
   __complex__ int *x = &(__complex__ int){1};
 }
 
 const _Complex double test9const = 0;
+// CHECK-LABEL: define dso_local { double, double } @test9func(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[RETVAL:%.*]] = alloca { double, double }, align 8
+// CHECK-NEXT:    [[RETVAL_REALP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[RETVAL]], i32 0, i32 0
+// CHECK-NEXT:    [[RETVAL_IMAGP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[RETVAL]], i32 0, i32 1
+// CHECK-NEXT:    store double 0.000000e+00, ptr [[RETVAL_REALP]], align 8
+// CHECK-NEXT:    store double 0.000000e+00, ptr [[RETVAL_IMAGP]], align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load { double, double }, ptr [[RETVAL]], 
align 8
+// CHECK-NEXT:    ret { double, double } [[TMP0]]
+//
 _Complex double test9func(void) { return test9const; }
 
 // D6217
+// CHECK-LABEL: define dso_local void @t91(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[C:%.*]] = alloca [0 x i8], align 1
+// CHECK-NEXT:    br i1 false, label %[[COND_TRUE:.*]], label 
%[[COND_FALSE:.*]]
+// CHECK:       [[COND_TRUE]]:
+// CHECK-NEXT:    br label %[[COND_END:.*]]
+// CHECK:       [[COND_FALSE]]:
+// CHECK-NEXT:    br label %[[COND_END]]
+// CHECK:       [[COND_END]]:
+// CHECK-NEXT:    [[COND_R:%.*]] = phi double [ 2.000000e+00, %[[COND_TRUE]] 
], [ 2.000000e+00, %[[COND_FALSE]] ]
+// CHECK-NEXT:    [[COND_I:%.*]] = phi double [ 0.000000e+00, %[[COND_TRUE]] 
], [ 0.000000e+00, %[[COND_FALSE]] ]
+// CHECK-NEXT:    ret void
+//
 void t91(void) {
   // Check for proper type promotion of conditional expression
   char c[(int)(sizeof(typeof((0 ? 2.0f : (_Complex double) 2.0f))) - 
sizeof(_Complex double))];
@@ -106,6 +539,20 @@ void t91(void) {
   (0 ? 2.0f : (_Complex double) 2.0f);
 }
 
+// CHECK-LABEL: define dso_local void @t92(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[C:%.*]] = alloca [0 x i8], align 1
+// CHECK-NEXT:    br i1 false, label %[[COND_TRUE:.*]], label 
%[[COND_FALSE:.*]]
+// CHECK:       [[COND_TRUE]]:
+// CHECK-NEXT:    br label %[[COND_END:.*]]
+// CHECK:       [[COND_FALSE]]:
+// CHECK-NEXT:    br label %[[COND_END]]
+// CHECK:       [[COND_END]]:
+// CHECK-NEXT:    [[COND_R:%.*]] = phi double [ 2.000000e+00, %[[COND_TRUE]] 
], [ 2.000000e+00, %[[COND_FALSE]] ]
+// CHECK-NEXT:    [[COND_I:%.*]] = phi double [ 0.000000e+00, %[[COND_TRUE]] 
], [ 0.000000e+00, %[[COND_FALSE]] ]
+// CHECK-NEXT:    ret void
+//
 void t92(void) {
   // Check for proper type promotion of conditional expression
   char c[(int)(sizeof(typeof((0 ? (_Complex double) 2.0f : 2.0f))) - 
sizeof(_Complex double))];
@@ -113,3 +560,36 @@ void t92(void) {
   (0 ? (_Complex double) 2.0f : 2.0f);
 }
 
+// CHECK-LABEL: define dso_local void @real_on_scalar_with_type_promotion(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[A:%.*]] = alloca { half, half }, align 2
+// CHECK-NEXT:    [[B:%.*]] = alloca half, align 2
+// CHECK-NEXT:    [[A_REALP:%.*]] = getelementptr inbounds nuw { half, half }, 
ptr [[A]], i32 0, i32 0
+// CHECK-NEXT:    [[A_REAL:%.*]] = load half, ptr [[A_REALP]], align 2
+// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[A_REAL]] to float
+// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[EXT]] to half
+// CHECK-NEXT:    store half [[UNPROMOTION]], ptr [[B]], align 2
+// CHECK-NEXT:    ret void
+//
+void real_on_scalar_with_type_promotion() {
+  _Float16 _Complex a;
+  _Float16 b = __real__(__real__ a);
+}
+
+// CHECK-LABEL: define dso_local void @imag_on_scalar_with_type_promotion(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[A:%.*]] = alloca { half, half }, align 2
+// CHECK-NEXT:    [[B:%.*]] = alloca half, align 2
+// CHECK-NEXT:    [[A_IMAGP:%.*]] = getelementptr inbounds nuw { half, half }, 
ptr [[A]], i32 0, i32 1
+// CHECK-NEXT:    [[A_IMAG:%.*]] = load half, ptr [[A_IMAGP]], align 2
+// CHECK-NEXT:    [[EXT:%.*]] = fpext half [[A_IMAG]] to float
+// CHECK-NEXT:    [[UNPROMOTION:%.*]] = fptrunc float [[EXT]] to half
+// CHECK-NEXT:    store half [[UNPROMOTION]], ptr [[B]], align 2
+// CHECK-NEXT:    ret void
+//
+void imag_on_scalar_with_type_promotion() {
+  _Float16 _Complex a;
+  _Float16 b = __real__(__imag__ a);
+}


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

Reply via email to