From 8d26593ba5e614b9f84dcfeb0d4b7f6641631b1c Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Wed, 24 Sep 2025 22:24:12 +0200 Subject: [PATCH 1/2] [Clang] Fix Codegen UO real/imag crash on scalar with type promotion --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/CodeGen/CGExprScalar.cpp | 31 +++++++++++++++++------------- clang/test/CodeGen/complex.c | 9 +++++++++ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 70c82b090107a..0937b154dbd4a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -558,6 +558,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..83c0d7dbb0dbc 100644 --- a/clang/test/CodeGen/complex.c +++ b/clang/test/CodeGen/complex.c @@ -113,3 +113,12 @@ void t92(void) { (0 ? (_Complex double) 2.0f : 2.0f); } +void real_on_scalar_with_type_promotion() { + _Float16 _Complex a; + _Float16 b = __real__(__real__ a); +} + +void imag_on_scalar_with_type_promotion() { + _Float16 _Complex a; + _Float16 b = __real__(__imag__ a); +} From fd301026aabda7ca7c07516cc3fc01a406ea9fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CAmr?= Date: Thu, 25 Sep 2025 23:42:53 +0200 Subject: [PATCH 2/2] Convert complex.c test to use update_cc_test_checks --- clang/test/CodeGen/complex.c | 473 ++++++++++++++++++++++++++++++++++- 1 file changed, 472 insertions(+), 1 deletion(-) diff --git a/clang/test/CodeGen/complex.c b/clang/test/CodeGen/complex.c index 83c0d7dbb0dbc..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,11 +560,35 @@ 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);