diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1330,6 +1330,22 @@ } } + if (SrcType->isFloatingType() && DstType->isFloatingType()) { + // Handle cast between PPC double-double and IEEE 128-bit float types. + const auto *SrcSemantics = &CGF.getContext().getFloatTypeSemantics(SrcType); + const auto *DstSemantics = &CGF.getContext().getFloatTypeSemantics(DstType); + if (SrcSemantics == &llvm::APFloat::PPCDoubleDouble() && + DstSemantics == &llvm::APFloat::IEEEquad()) + return Builder.CreateCall( + CGF.CGM.getIntrinsic(llvm::Intrinsic::ppc_convert_ppcf128_to_f128), + Src); + if (SrcSemantics == &llvm::APFloat::IEEEquad() && + DstSemantics == &llvm::APFloat::PPCDoubleDouble()) + return Builder.CreateCall( + CGF.CGM.getIntrinsic(llvm::Intrinsic::ppc_convert_f128_to_ppcf128), + Src); + } + // Ignore conversions like int -> uint. if (SrcTy == DstTy) { if (Opts.EmitImplicitIntegerSignChangeChecks) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1537,7 +1537,7 @@ // At this point, we have two different arithmetic types. // Diagnose attempts to convert between __ibm128, __float128 and long double - // where such conversions currently can't be handled. + // in arithmetic or comparison. if (unsupportedTypeConversion(*this, LHSType, RHSType)) return QualType(); @@ -9304,11 +9304,6 @@ return Incompatible; } - // Diagnose attempts to convert between __ibm128, __float128 and long double - // where such conversions currently can't be handled. - if (unsupportedTypeConversion(*this, LHSType, RHSType)) - return Incompatible; - // Disallow assigning a _Complex to a real type in C++ mode since it simply // discards the imaginary part. if (getLangOpts().CPlusPlus && RHSType->getAs() && diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1869,25 +1869,10 @@ SCS.Second = ICK_Complex_Real; FromType = ToType.getUnqualifiedType(); } else if (FromType->isRealFloatingType() && ToType->isRealFloatingType()) { - // FIXME: disable conversions between long double, __ibm128 and __float128 - // if their representation is different until there is back end support - // We of course allow this conversion if long double is really double. - // Conversions between bfloat and other floats are not permitted. if (FromType == S.Context.BFloat16Ty || ToType == S.Context.BFloat16Ty) return false; - // Conversions between IEEE-quad and IBM-extended semantics are not - // permitted. - const llvm::fltSemantics &FromSem = - S.Context.getFloatTypeSemantics(FromType); - const llvm::fltSemantics &ToSem = S.Context.getFloatTypeSemantics(ToType); - if ((&FromSem == &llvm::APFloat::PPCDoubleDouble() && - &ToSem == &llvm::APFloat::IEEEquad()) || - (&FromSem == &llvm::APFloat::IEEEquad() && - &ToSem == &llvm::APFloat::PPCDoubleDouble())) - return false; - // Floating point conversions (C++ 4.8). SCS.Second = ICK_Floating_Conversion; FromType = ToType.getUnqualifiedType(); diff --git a/clang/test/CodeGen/ibm128-cast.c b/clang/test/CodeGen/ibm128-cast.c --- a/clang/test/CodeGen/ibm128-cast.c +++ b/clang/test/CodeGen/ibm128-cast.c @@ -2,11 +2,18 @@ // RUN: -target-feature +float128 -mabi=ieeelongdouble -fsyntax-only -Wno-unused %s // RUN: %clang_cc1 -emit-llvm -triple powerpc64le-unknown-unknown -verify \ // RUN: -target-feature +float128 -fsyntax-only -Wno-unused %s +// RUN: %clang_cc1 -emit-llvm -triple powerpc64le-unknown-unknown -DCODEGEN \ +// RUN: -target-feature +float128 -mabi=ieeelongdouble %s -o - | FileCheck %s -__float128 cast1(__ibm128 x) { return x; } // expected-error {{returning '__ibm128' from a function with incompatible result type '__float128'}} +// CHECK: define dso_local fp128 @cast1(ppc_fp128 %{{.+}}) +// CHECK: %{{.+}} = call fp128 @llvm.ppc.convert.ppcf128.to.f128(ppc_fp128 %{{.+}}) +__float128 cast1(__ibm128 x) { return x; } // expected-no-error -__ibm128 cast2(__float128 x) { return x; } // expected-error {{returning '__float128' from a function with incompatible result type '__ibm128'}} +// IEEE: define dso_local ppc_fp128 @cast2(fp128 %{{.+}}) +// IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) +__ibm128 cast2(__float128 x) { return x; } // expected-no-error +#ifndef CODEGEN __ibm128 gf; void narrow(double *d, float *f) { @@ -17,9 +24,9 @@ } #ifdef __LONG_DOUBLE_IEEE128__ -long double cast3(__ibm128 x) { return x; } // expected-error {{returning '__ibm128' from a function with incompatible result type 'long double'}} +long double cast3(__ibm128 x) { return x; } // expected-no-error -__ibm128 cast4(long double x) { return x; } // expected-error {{returning 'long double' from a function with incompatible result type '__ibm128'}} +__ibm128 cast4(long double x) { return x; } // expected-no-error void imp_cast(__ibm128 w, __float128 q, long double l, _Bool b) { w + q; // expected-error {{invalid operands to binary expression ('__ibm128' and '__float128')}} @@ -30,10 +37,10 @@ q *w; // expected-error {{invalid operands to binary expression ('__float128' and '__ibm128')}} q / w; // expected-error {{invalid operands to binary expression ('__float128' and '__ibm128')}} w / l; // expected-error {{invalid operands to binary expression ('__ibm128' and 'long double')}} - w = q; // expected-error {{assigning to '__ibm128' from incompatible type '__float128'}} - q = w; // expected-error {{assigning to '__float128' from incompatible type '__ibm128'}} - l = w; // expected-error {{assigning to 'long double' from incompatible type '__ibm128'}} - w = l; // expected-error {{assigning to '__ibm128' from incompatible type 'long double'}} + w = q; // expected-no-error {{assigning to '__ibm128' from incompatible type '__float128'}} + q = w; // expected-no-error {{assigning to '__float128' from incompatible type '__ibm128'}} + l = w; // expected-no-error {{assigning to 'long double' from incompatible type '__ibm128'}} + w = l; // expected-no-error {{assigning to '__ibm128' from incompatible type 'long double'}} b ? q : w; // expected-error {{incompatible operand types ('__float128' and '__ibm128')}} !b ? w : l; // expected-error {{incompatible operand types ('__ibm128' and 'long double')}} } @@ -51,11 +58,12 @@ q *w; // expected-error {{invalid operands to binary expression ('__float128' and '__ibm128')}} q / w; // expected-error {{invalid operands to binary expression ('__float128' and '__ibm128')}} w / l; // expected-no-error {{invalid operands to binary expression ('__ibm128' and 'long double')}} - w = q; // expected-error {{assigning to '__ibm128' from incompatible type '__float128'}} - q = w; // expected-error {{assigning to '__float128' from incompatible type '__ibm128'}} + w = q; // expected-no-error {{assigning to '__ibm128' from incompatible type '__float128'}} + q = w; // expected-no-error {{assigning to '__float128' from incompatible type '__ibm128'}} l = w; // expected-no-error {{assigning to 'long double' from incompatible type '__ibm128'}} w = l; // expected-no-error {{assigning to '__ibm128' from incompatible type 'long double'}} b ? q : w; // expected-error {{incompatible operand types ('__float128' and '__ibm128')}} - !b ? w : l; // expected-no-error {{incompatible operand types ('__ibm128' and 'long double')}} + !b ? w : l; // expected-no-error } #endif +#endif diff --git a/clang/test/Sema/float128-ld-incompatibility.cpp b/clang/test/Sema/float128-ld-incompatibility.cpp --- a/clang/test/Sema/float128-ld-incompatibility.cpp +++ b/clang/test/Sema/float128-ld-incompatibility.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 \ // RUN: -triple powerpc64le-unknown-linux-gnu -target-cpu pwr9 \ -// RUN: -target-feature +float128 %s +// RUN: -Wno-unused-value -Wno-parentheses -target-feature +float128 %s // RUN: %clang_cc1 -fsyntax-only -std=c++11 -triple x86_64-unknown-linux-gnu -Wno-unused-value -Wno-parentheses %s __float128 qf(); @@ -9,8 +9,8 @@ #ifdef __PPC__ // FIXME: once operations between long double and __float128 are implemented for // targets where the types are different, these next two will change -long double ld{qf()}; // expected-error {{cannot initialize a variable of type 'long double' with an rvalue of type '__float128'}} -__float128 q{ldf()}; // expected-error {{cannot initialize a variable of type '__float128' with an rvalue of type 'long double'}} +long double ld{qf()}; // expected-error {{non-constant-expression cannot be narrowed from type '__float128' to 'long double' in initializer list}} expected-note {{insert an explicit cast to silence this issue}} +__float128 q{ldf()}; // expected-no-error auto test1(__float128 q, long double ld) -> decltype(q + ld) { // expected-error {{invalid operands to binary expression ('__float128' and 'long double')}} return q + ld; // expected-error {{invalid operands to binary expression ('__float128' and 'long double')}} @@ -33,7 +33,9 @@ q * ld; // expected-error {{invalid operands to binary expression ('__float128' and 'long double')}} ld / q; // expected-error {{invalid operands to binary expression ('long double' and '__float128')}} q / ld; // expected-error {{invalid operands to binary expression ('__float128' and 'long double')}} - ld = q; // expected-error {{assigning to 'long double' from incompatible type '__float128'}} - q = ld; // expected-error {{assigning to '__float128' from incompatible type 'long double'}} + ld = q; // expected-no-error {{assigning to 'long double' from incompatible type '__float128'}} + q = ld; // expected-no-error {{assigning to '__float128' from incompatible type 'long double'}} q + b ? q : ld; // expected-error {{incompatible operand types ('__float128' and 'long double')}} + q += ld; // expected-error {{invalid operands to binary expression ('__float128' and 'long double')}} + ld /= q; // expected-error {{invalid operands to binary expression ('long double' and '__float128')}} }