Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -522,6 +522,7 @@ def NullPointerArithmetic : DiagGroup<"null-pointer-arithmetic", [GNUNullPointerArithmetic]>; def NullPointerSubtraction : DiagGroup<"null-pointer-subtraction">; +def FloatMaybeInaccurate : DiagGroup<"float-maybe-inaccurate">; def : DiagGroup<"effc++", [NonVirtualDtor]>; def OveralignedType : DiagGroup<"over-aligned">; def OldStyleCast : DiagGroup<"old-style-cast">; Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6583,6 +6583,13 @@ "performing pointer subtraction with a null pointer %select{has|may have}0 undefined behavior">, InGroup, DefaultIgnore; +def warn_float_maybe_inaccurate_cast : Warning< + "floating point casting may be inaccurate due to low default value of x87 precision control">, + InGroup; +def warn_float_maybe_inaccurate_arith : Warning< + "floating point arithmetic may be inaccurate due to low default value of x87 precision control">, + InGroup; + def warn_floatingpoint_eq : Warning< "comparing floating point with == or != is unsafe">, InGroup>, DefaultIgnore; Index: clang/lib/Sema/SemaCast.cpp =================================================================== --- clang/lib/Sema/SemaCast.cpp +++ clang/lib/Sema/SemaCast.cpp @@ -146,6 +146,8 @@ // Language specific cast restrictions for address spaces. void checkAddressSpaceCast(QualType SrcType, QualType DestType); + void checkFloatCast(); + void checkCastAlign() { Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); } @@ -1253,6 +1255,7 @@ checkCastAlign(); if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) checkObjCConversion(Sema::CCK_OtherCast); + checkFloatCast(); } else { SrcExpr = ExprError(); } @@ -2641,6 +2644,35 @@ } } +void CastOperation::checkFloatCast() { + const BuiltinType *SourceBT = SrcExpr.get()->getType()->getAs(); + const BuiltinType *TargetBT = DestType->getAs(); + + if (!SourceBT || !TargetBT) + return; + + if (!SourceBT->isFloatingType() && !TargetBT->isFloatingType() || + SourceBT->getKind() == TargetBT->getKind()) + return; + + const clang::TargetInfo &TI = Self.Context.getTargetInfo(); + const llvm::Triple &TT = TI.getTriple(); + + const BuiltinType::Kind SourceKind = SourceBT->getKind(); + const BuiltinType::Kind TargetKind = TargetBT->getKind(); + + // On Windows, the default precision control on x87 is only 56-bit. + if (TT.isOSWindows() && TT.isX86() && TI.hasFeature("x87") && + ((!TI.hasFeature("sse2") && (SourceKind == BuiltinType::LongLong || + SourceKind == BuiltinType::ULongLong || + SourceKind == BuiltinType::Double || + TargetKind == BuiltinType::Double)) || + (SourceKind == BuiltinType::LongDouble || + TargetKind == BuiltinType::LongDouble))) + Self.Diag(OpRange.getBegin(), diag::warn_float_maybe_inaccurate_arith) + << OpRange; +} + bool Sema::ShouldSplatAltivecScalarInCast(const VectorType *VecTy) { bool SrcCompatXL = this->getLangOpts().getAltivecSrcCompat() == LangOptions::AltivecSrcCompatKind::XL; @@ -2816,6 +2848,7 @@ Self.Diag(OpRange.getBegin(), DiagID) << SrcExpr.get()->getType() << DestType << OpRange; + checkFloatCast(); } else { SrcExpr = ExprError(); } @@ -3200,6 +3233,8 @@ if (Kind == CK_BitCast) checkCastAlign(); + + checkFloatCast(); } void CastOperation::CheckBuiltinBitCast() { Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ clang/lib/Sema/SemaChecking.cpp @@ -13928,6 +13928,23 @@ DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_double_promotion); } + + const TargetInfo &TI = S.Context.getTargetInfo(); + const llvm::Triple &TT = TI.getTriple(); + + const BuiltinType::Kind SourceKind = SourceBT->getKind(); + const BuiltinType::Kind TargetKind = TargetBT->getKind(); + + // On Windows, the default precision control on x87 is only 56-bit. + if (TT.isOSWindows() && TT.isX86() && TI.hasFeature("x87") && + SourceBT->getKind() != TargetBT->getKind() && + ((!TI.hasFeature("sse2") && (SourceKind == BuiltinType::Double || + TargetKind == BuiltinType::Double)) || + (SourceKind == BuiltinType::LongDouble || + TargetKind == BuiltinType::LongDouble))) + S.Diag(E->getBeginLoc(), diag::warn_float_maybe_inaccurate_cast) + << E->getExprLoc(); + return; } @@ -14077,6 +14094,21 @@ diag::warn_impcast_integer_float_precision); } } + + const TargetInfo &TI = S.Context.getTargetInfo(); + const llvm::Triple &TT = TI.getTriple(); + + const BuiltinType::Kind SourceKind = SourceBT->getKind(); + const BuiltinType::Kind TargetKind = TargetBT->getKind(); + + // On Windows, the default precision control on x87 is only 56-bit. + if (TT.isOSWindows() && TT.isX86() && TI.hasFeature("x87") && + ((!TI.hasFeature("sse2") && (SourceKind == BuiltinType::LongLong || + SourceKind == BuiltinType::ULongLong || + TargetKind == BuiltinType::Double)) || + TargetKind == BuiltinType::LongDouble)) + S.Diag(E->getBeginLoc(), diag::warn_float_maybe_inaccurate_cast) + << E->getExprLoc(); } DiagnoseNullConversion(S, E, T, CC); Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -15093,6 +15093,29 @@ return HasVectorOfHalfType(E0) && (!E1 || HasVectorOfHalfType(E1)); } +static void checkFloatSupport(Sema &S, ExprResult &LHS, ExprResult &RHS, + SourceLocation OpLoc) { + const BuiltinType *LBT = LHS.get()->getType()->getAs(); + const BuiltinType *RBT = RHS.get()->getType()->getAs(); + + if (!LBT || !RBT) + return; + + if (!LBT->isFloatingType() && !RBT->isFloatingType()) + return; + + const TargetInfo &TI = S.Context.getTargetInfo(); + const llvm::Triple &TT = TI.getTriple(); + + // On Windows, the default precision control on x87 is only 56-bit. + if (TT.isOSWindows() && TT.isX86() && TI.hasFeature("x87") && + ((!TI.hasFeature("sse2") && (LBT->getKind() == BuiltinType::Double || + RBT->getKind() == BuiltinType::Double)) || + (LBT->getKind() == BuiltinType::LongDouble || + RBT->getKind() == BuiltinType::LongDouble))) + S.Diag(OpLoc, diag::warn_float_maybe_inaccurate_arith) << OpLoc; +} + /// CreateBuiltinBinOp - Creates a new built-in binary operation with /// operator @p Opc at location @c TokLoc. This routine only supports /// built-in operations; ActOnBinOp handles overloaded operators. @@ -15205,17 +15228,21 @@ ConvertHalfVec = true; ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false, Opc == BO_Div); + checkFloatSupport(*this, LHS, RHS, OpLoc); break; case BO_Rem: ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc); + checkFloatSupport(*this, LHS, RHS, OpLoc); break; case BO_Add: ConvertHalfVec = true; ResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc); + checkFloatSupport(*this, LHS, RHS, OpLoc); break; case BO_Sub: ConvertHalfVec = true; ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc); + checkFloatSupport(*this, LHS, RHS, OpLoc); break; case BO_Shl: case BO_Shr: @@ -15259,6 +15286,7 @@ if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc); + checkFloatSupport(*this, LHS, RHS, OpLoc); break; case BO_RemAssign: CompResultTy = CheckRemainderOperands(LHS, RHS, OpLoc, true); @@ -15266,6 +15294,7 @@ if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc); + checkFloatSupport(*this, LHS, RHS, OpLoc); break; case BO_AddAssign: ConvertHalfVec = true; @@ -15273,6 +15302,7 @@ if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc); + checkFloatSupport(*this, LHS, RHS, OpLoc); break; case BO_SubAssign: ConvertHalfVec = true; @@ -15280,6 +15310,7 @@ if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc); + checkFloatSupport(*this, LHS, RHS, OpLoc); break; case BO_ShlAssign: case BO_ShrAssign: Index: llvm/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/lib/Target/X86/X86ISelLowering.cpp +++ llvm/lib/Target/X86/X86ISelLowering.cpp @@ -21368,6 +21368,10 @@ if (VT == MVT::f128 || !Subtarget.hasX87()) return SDValue(); + // On Windows, the default precision control on x87 is only 56-bit. + if (SrcVT == MVT::i64 && UseSSEReg && Subtarget.isOSWindows()) + return SDValue(); + SDValue ValueToStore = Src; if (SrcVT == MVT::i64 && Subtarget.hasSSE2() && !Subtarget.is64Bit()) // Bitcasting to f64 here allows us to do a single 64-bit store from @@ -21824,7 +21828,9 @@ if (SDValue Extract = vectorizeExtractedCast(Op, DAG, Subtarget)) return Extract; - if (Subtarget.hasAVX512() && isScalarFPTypeInSSEReg(DstVT) && + bool UseSSEReg = isScalarFPTypeInSSEReg(DstVT); + + if (Subtarget.hasAVX512() && UseSSEReg && (SrcVT == MVT::i32 || (SrcVT == MVT::i64 && Subtarget.is64Bit()))) { // Conversions from unsigned i32 to f32/f64 are legal, // using VCVTUSI2SS/SD. Same for i64 in 64-bit mode. @@ -21859,6 +21865,9 @@ (DstVT == MVT::f32 || DstVT == MVT::f64)) return SDValue(); + if (!Subtarget.hasX87()) + return SDValue(); + // Make a 64-bit buffer, and use it to build an FILD. SDValue StackSlot = DAG.CreateStackTemporary(MVT::i64, 8); int SSFI = cast(StackSlot)->getIndex(); @@ -21880,6 +21889,11 @@ } assert(SrcVT == MVT::i64 && "Unexpected type in UINT_TO_FP"); + + // On Windows, the default precision control on x87 is only 56-bit. + if (UseSSEReg && Subtarget.isOSWindows()) + return SDValue(); + SDValue ValueToStore = Src; if (isScalarFPTypeInSSEReg(Op.getValueType()) && !Subtarget.is64Bit()) { // Bitcasting to f64 here allows us to do a single 64-bit store from