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 @@ -1325,6 +1325,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 @@ -1197,34 +1197,6 @@ /*ConvertInt=*/!IsCompAssign); } -/// Diagnose attempts to convert between __float128, __ibm128 and -/// long double if there is no support for such conversion. -/// Helper function of UsualArithmeticConversions(). -static bool unsupportedTypeConversion(const Sema &S, QualType LHSType, - QualType RHSType) { - // No issue if either is not a floating point type. - if (!LHSType->isFloatingType() || !RHSType->isFloatingType()) - return false; - - // No issue if both have the same 128-bit float semantics. - auto *LHSComplex = LHSType->getAs(); - auto *RHSComplex = RHSType->getAs(); - - QualType LHSElem = LHSComplex ? LHSComplex->getElementType() : LHSType; - QualType RHSElem = RHSComplex ? RHSComplex->getElementType() : RHSType; - - const llvm::fltSemantics &LHSSem = S.Context.getFloatTypeSemantics(LHSElem); - const llvm::fltSemantics &RHSSem = S.Context.getFloatTypeSemantics(RHSElem); - - if ((&LHSSem != &llvm::APFloat::PPCDoubleDouble() || - &RHSSem != &llvm::APFloat::IEEEquad()) && - (&LHSSem != &llvm::APFloat::IEEEquad() || - &RHSSem != &llvm::APFloat::PPCDoubleDouble())) - return false; - - return true; -} - typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType); namespace { @@ -1534,11 +1506,6 @@ // 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. - if (unsupportedTypeConversion(*this, LHSType, RHSType)) - return QualType(); - // Handle complex types first (C99 6.3.1.8p1). if (LHSType->isComplexType() || RHSType->isComplexType()) return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType, @@ -8362,15 +8329,6 @@ QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); - // Diagnose attempts to convert between __ibm128, __float128 and long double - // where such conversions currently can't be handled. - if (unsupportedTypeConversion(*this, LHSTy, RHSTy)) { - Diag(QuestionLoc, - diag::err_typecheck_cond_incompatible_operands) << LHSTy << RHSTy - << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - return QualType(); - } - // OpenCL v2.0 s6.12.5 - Blocks cannot be used as expressions of the ternary // selection operator (?:). if (getLangOpts().OpenCL && @@ -9297,11 +9255,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/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 @@ -1,61 +1,115 @@ -// RUN: %clang_cc1 -emit-llvm -triple powerpc64le-unknown-unknown -verify \ -// 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 -S -emit-llvm -triple powerpc64le-unknown-unknown \ +// RUN: -target-feature +float128 -mabi=ieeelongdouble -Wno-unused %s \ +// RUN: -o - | FileCheck %s --check-prefix=IEEE +// RUN: %clang_cc1 -S -emit-llvm -triple powerpc64le-unknown-unknown \ +// RUN: -target-feature +float128 -Wno-unused %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 %{{.+}}) +// IEEE: define dso_local fp128 @cast1(ppc_fp128 %{{.+}}) +// IEEE: %{{.+}} = call fp128 @llvm.ppc.convert.ppcf128.to.f128(ppc_fp128 %{{.+}}) +__float128 cast1(__ibm128 x) { return x; } -__ibm128 cast2(__float128 x) { return x; } // expected-error {{returning '__float128' from a function with incompatible result type '__ibm128'}} +// CHECK: define dso_local ppc_fp128 @cast2(fp128 %{{.+}}) +// CHECK: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) +// 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; } __ibm128 gf; +// CHECK: define dso_local void @narrow(double* %{{.+}}, float* %{{.+}}) +// IEEE: define dso_local void @narrow(double* %{{.+}}, float* %{{.+}}) void narrow(double *d, float *f) { __ibm128 v = gf; - gf = *d; // expected-no-error {{assigning to '__ibm128' from incompatible type 'double'}} - *f = v; // expected-no-error {{assigning to 'float' from incompatible type '__ibm128'}} - *d = gf + *f; // expected-no-error {{invalid operands to binary expression ('__ibm128' and 'float')}} + // CHECK: %{{.+}} = fpext double %{{.+}} to ppc_fp128 + // IEEE: %{{.+}} = fpext double %{{.+}} to ppc_fp128 + gf = *d; + // CHECK: %{{.+}} = fptrunc ppc_fp128 %{{.+}} to float + // IEEE: %{{.+}} = fptrunc ppc_fp128 %{{.+}} to float + *f = v; + // CHECK: %{{.+}} = fpext float %{{.+}} to ppc_fp128 + // CHECK: %{{.+}} = fadd ppc_fp128 %{{.+}}, %{{.+}} + // CHECK: %{{.+}} = fptrunc ppc_fp128 %{{.+}} to double + // IEEE: %{{.+}} = fpext float %{{.+}} to ppc_fp128 + // IEEE: %{{.+}} = fadd ppc_fp128 %{{.+}}, %{{.+}} + // IEEE: %{{.+}} = fptrunc ppc_fp128 %{{.+}} to double + *d = gf + *f; } -#ifdef __LONG_DOUBLE_IEEE128__ -long double cast3(__ibm128 x) { return x; } // expected-error {{returning '__ibm128' from a function with incompatible result type 'long double'}} +// CHECK: define dso_local ppc_fp128 @cast3(ppc_fp128 %{{.+}}) +// CHECK-NOT: call ppc_fp128 +// IEEE: define dso_local fp128 @cast3(ppc_fp128 %{{.+}}) +// IEEE: %{{.+}} = call fp128 @llvm.ppc.convert.ppcf128.to.f128(ppc_fp128 %{{.+}}) +long double cast3(__ibm128 x) { return x; } -__ibm128 cast4(long double x) { return x; } // expected-error {{returning 'long double' from a function with incompatible result type '__ibm128'}} +// CHECK: define dso_local ppc_fp128 @cast4(ppc_fp128 %{{.+}}) +// CHECK-NOT: %{{.+}} = call ppc_fp128 +// IEEE: define dso_local ppc_fp128 @cast4(fp128 %{{.+}}) +// IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) +__ibm128 cast4(long double x) { return x; } +// CHECK: define dso_local void @imp_cast(ppc_fp128 %{{.+}}, fp128 %{{.+}}, ppc_fp128 %{{.+}}, i1 zeroext %{{.+}}) +// IEEE: define dso_local void @imp_cast(ppc_fp128 %{{.+}}, fp128 %{{.+}}, fp128 %{{.+}}, i1 zeroext %{{.+}}) void imp_cast(__ibm128 w, __float128 q, long double l, _Bool b) { - w + q; // expected-error {{invalid operands to binary expression ('__ibm128' and '__float128')}} - l + w; // expected-error {{invalid operands to binary expression ('long double' 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 *l; // expected-error {{invalid operands to binary expression ('__ibm128' and 'long double')}} - 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'}} - b ? q : w; // expected-error {{incompatible operand types ('__float128' and '__ibm128')}} - !b ? w : l; // expected-error {{incompatible operand types ('__ibm128' and 'long double')}} + // CHECK: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // CHECK: %{{.+}} = fadd ppc_fp128 %{{.+}}, %{{.+}} + // IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // IEEE: %{{.+}} = fadd ppc_fp128 %{{.+}}, %{{.+}} + w + q; + // CHECK: %{{.+}} = fadd ppc_fp128 %{{.+}}, %{{.+}} + // IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // IEEE: %{{.+}} = fadd ppc_fp128 %{{.+}}, %{{.+}} + l + w; + // CHECK: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // CHECK: %{{.+}} = fsub ppc_fp128 %{{.+}}, %{{.+}} + // IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // IEEE: %{{.+}} = fsub ppc_fp128 %{{.+}}, %{{.+}} + q - w; + // CHECK: %{{.+}} = fsub ppc_fp128 %{{.+}}, %{{.+}} + // IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // IEEE: %{{.+}} = fsub ppc_fp128 %{{.+}}, %{{.+}} + w - l; + // CHECK: %{{.+}} = fmul ppc_fp128 %{{.+}}, %{{.+}} + // IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // IEEE: %{{.+}} = fmul ppc_fp128 %{{.+}}, %{{.+}} + w *l; + // CHECK: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // CHECK: %{{.+}} = fmul ppc_fp128 %{{.+}}, %{{.+}} + // IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // IEEE: %{{.+}} = fmul ppc_fp128 %{{.+}}, %{{.+}} + q *w; + // CHECK: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // CHECK: %{{.+}} = fdiv ppc_fp128 %{{.+}}, %{{.+}} + // IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // IEEE: %{{.+}} = fdiv ppc_fp128 %{{.+}}, %{{.+}} + q / w; + // CHECK: %{{.+}} = fdiv ppc_fp128 %{{.+}}, %{{.+}} + // IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // IEEE: %{{.+}} = fdiv ppc_fp128 %{{.+}}, %{{.+}} + w / l; + // CHECK: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // CHECK: store ppc_fp128 %{{.+}}, ppc_fp128* %{{.+}}, align 16 + // IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // IEEE: store ppc_fp128 %{{.+}}, ppc_fp128* %{{.+}}, align 16 + w = q; + // CHECK: %{{.+}} = call fp128 @llvm.ppc.convert.ppcf128.to.f128(ppc_fp128 %{{.+}}) + // CHECK: store fp128 %{{.+}}, fp128* %{{.+}}, align 16 + // IEEE: %{{.+}} = call fp128 @llvm.ppc.convert.ppcf128.to.f128(ppc_fp128 %{{.+}}) + // IEEE: store fp128 %{{.+}}, fp128* %{{.+}}, align 16 + q = w; + // CHECK: store ppc_fp128 %{{.+}}, ppc_fp128* %{{.+}}, align 16 + // IEEE: %{{.+}} = call fp128 @llvm.ppc.convert.ppcf128.to.f128(ppc_fp128 %{{.+}}) + // IEEE: store fp128 %{{.+}}, fp128* %{{.+}}, align 16 + l = w; + // CHECK: store ppc_fp128 %{{.+}}, ppc_fp128* %{{.+}}, align 16 + // IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // IEEE: store ppc_fp128 %{{.+}}, ppc_fp128* %{{.+}}, align 16 + w = l; + // CHECK: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + // IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + b ? q : w; + // CHECK-NOT: call ppc_fp128 + // IEEE: %{{.+}} = call ppc_fp128 @llvm.ppc.convert.f128.to.ppcf128(fp128 %{{.+}}) + !b ? w : l; } -#elif __LONG_DOUBLE_IBM128__ -long double cast3(__ibm128 x) { return x; } // expected-no-error {{returning '__ibm128' from a function with incompatible result type 'long double'}} - -__ibm128 cast4(long double x) { return x; } // expected-no-error {{returning 'long double' from a function with incompatible result type '__ibm128'}} - -void imp_cast(__ibm128 w, __float128 q, long double l, _Bool b) { - w + q; // expected-error {{invalid operands to binary expression ('__ibm128' and '__float128')}} - l + w; // expected-no-error {{invalid operands to binary expression ('long double' 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 *l; // expected-no-error {{invalid operands to binary expression ('__ibm128' and 'long double')}} - 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'}} - 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')}} -} -#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(); @@ -12,12 +12,12 @@ 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'}} -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')}} +auto test1(__float128 q, long double ld) -> decltype(q + ld) { // expected-no-error {{invalid operands to binary expression ('__float128' and 'long double')}} + return q + ld; // expected-no-error {{invalid operands to binary expression ('__float128' and 'long double')}} } -auto test2(long double a, __float128 b) -> decltype(a + b) { // expected-error {{invalid operands to binary expression ('long double' and '__float128')}} - return a + b; // expected-error {{invalid operands to binary expression ('long double' and '__float128')}} +auto test2(long double a, __float128 b) -> decltype(a + b) { // expected-eno-rror {{invalid operands to binary expression ('long double' and '__float128')}} + return a + b; // expected-no-error {{invalid operands to binary expression ('long double' and '__float128')}} } #endif @@ -25,15 +25,15 @@ long double ld; __float128 q; - 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 {{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 {{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 {{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-no-error {{invalid operands to binary expression ('long double' and '__float128')}} + q + ld; // expected-no-error {{invalid operands to binary expression ('__float128' and 'long double')}} + ld - q; // expected-no-error {{invalid operands to binary expression ('long double' and '__float128')}} + q - ld; // expected-no-error {{invalid operands to binary expression ('__float128' and 'long double')}} + ld * q; // expected-no-error {{invalid operands to binary expression ('long double' and '__float128')}} + q * ld; // expected-no-error {{invalid operands to binary expression ('__float128' and 'long double')}} + ld / q; // expected-no-error {{invalid operands to binary expression ('long double' and '__float128')}} + q / ld; // expected-no-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'}} - q + b ? q : ld; // expected-error {{incompatible operand types ('__float128' and 'long double')}} + q + b ? q : ld; // expected-no-error {{incompatible operand types ('__float128' and 'long double')}} }