diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 56b150ad38ed..a75d77747b53 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -585,7 +585,7 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc, } else { // Floating-point to integer or floating-point to floating-point. This has // undefined behavior if the source is +-Inf, NaN, or doesn't fit into the - // destination type. + // destination type (after truncation to an integer for float-to-integer). const llvm::fltSemantics &SrcSema = CGF.getContext().getFloatTypeSemantics(OrigSrcType); APFloat MaxSrc(SrcSema, APFloat::uninitialized); @@ -600,14 +600,22 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc, APFloat::opOverflow) // Don't need an overflow check for lower bound. Just check for // -Inf/NaN. - MinSrc = APFloat::getLargest(SrcSema, true); + MinSrc = APFloat::getInf(SrcSema, true); + else + // Find the largest value which is too small to represent (before + // truncation toward zero). + MinSrc.subtract(APFloat(SrcSema, 1), APFloat::rmTowardNegative); APSInt Max = APSInt::getMaxValue(Width, Unsigned); if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) & APFloat::opOverflow) // Don't need an overflow check for upper bound. Just check for // +Inf/NaN. - MaxSrc = APFloat::getLargest(SrcSema, false); + MaxSrc = APFloat::getInf(SrcSema, false); + else + // Find the smallest value which is too large to represent (before + // truncation toward zero). + MaxSrc.add(APFloat(SrcSema, 1), APFloat::rmTowardPositive); } else { const llvm::fltSemantics &DstSema = CGF.getContext().getFloatTypeSemantics(DstType); @@ -634,11 +642,19 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc, MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact); } - llvm::Value *GE = - Builder.CreateFCmpOGE(Src, llvm::ConstantFP::get(VMContext, MinSrc)); - llvm::Value *LE = - Builder.CreateFCmpOLE(Src, llvm::ConstantFP::get(VMContext, MaxSrc)); - Check = Builder.CreateAnd(GE, LE); + if (isa(DstTy)) { + llvm::Value *GE = + Builder.CreateFCmpOGT(Src, llvm::ConstantFP::get(VMContext, MinSrc)); + llvm::Value *LE = + Builder.CreateFCmpOLT(Src, llvm::ConstantFP::get(VMContext, MaxSrc)); + Check = Builder.CreateAnd(GE, LE); + } else { + llvm::Value *GE = + Builder.CreateFCmpOGE(Src, llvm::ConstantFP::get(VMContext, MinSrc)); + llvm::Value *LE = + Builder.CreateFCmpOLE(Src, llvm::ConstantFP::get(VMContext, MaxSrc)); + Check = Builder.CreateAnd(GE, LE); + } } // FIXME: Provide a SourceLocation. diff --git a/clang/test/CodeGen/catch-undef-behavior.c b/clang/test/CodeGen/catch-undef-behavior.c index 3e180a445b6a..bd4973c069cb 100644 --- a/clang/test/CodeGen/catch-undef-behavior.c +++ b/clang/test/CodeGen/catch-undef-behavior.c @@ -285,13 +285,13 @@ void int_fp16_overflow(int n, __fp16 *p) { // CHECK: @float_int_overflow // CHECK-TRAP: @float_int_overflow int float_int_overflow(float f) { - // CHECK: %[[GE:.*]] = fcmp oge float %[[F:.*]], 0xC1E0000000000000 - // CHECK: %[[LE:.*]] = fcmp ole float %[[F]], 0x41DFFFFFE0000000 + // CHECK: %[[GE:.*]] = fcmp ogt float %[[F:.*]], 0xC1E0000020000000 + // CHECK: %[[LE:.*]] = fcmp olt float %[[F]], 0x41E0000000000000 // CHECK: and i1 %[[GE]], %[[LE]] // CHECK: call void @__ubsan_handle_float_cast_overflow( - // CHECK-TRAP: %[[GE:.*]] = fcmp oge float %[[F:.*]], 0xC1E0000000000000 - // CHECK-TRAP: %[[LE:.*]] = fcmp ole float %[[F]], 0x41DFFFFFE0000000 + // CHECK-TRAP: %[[GE:.*]] = fcmp ogt float %[[F:.*]], 0xC1E0000020000000 + // CHECK-TRAP: %[[LE:.*]] = fcmp olt float %[[F]], 0x41E0000000000000 // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]] // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]] @@ -303,13 +303,13 @@ int float_int_overflow(float f) { // CHECK: @float_uint_overflow // CHECK-TRAP: @float_uint_overflow unsigned float_uint_overflow(float f) { - // CHECK: %[[GE:.*]] = fcmp oge float %[[F:.*]], 0.{{0*}}e+00 - // CHECK: %[[LE:.*]] = fcmp ole float %[[F]], 0x41EFFFFFE0000000 + // CHECK: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.{{0*}}e+00 + // CHECK: %[[LE:.*]] = fcmp olt float %[[F]], 0x41F0000000000000 // CHECK: and i1 %[[GE]], %[[LE]] // CHECK: call void @__ubsan_handle_float_cast_overflow( - // CHECK-TRAP: %[[GE:.*]] = fcmp oge float %[[F:.*]], 0.{{0*}}e+00 - // CHECK-TRAP: %[[LE:.*]] = fcmp ole float %[[F]], 0x41EFFFFFE0000000 + // CHECK-TRAP: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.{{0*}}e+00 + // CHECK-TRAP: %[[LE:.*]] = fcmp olt float %[[F]], 0x41F0000000000000 // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]] // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]] @@ -321,13 +321,13 @@ unsigned float_uint_overflow(float f) { // CHECK: @fp16_char_overflow // CHECK-TRAP: @fp16_char_overflow signed char fp16_char_overflow(__fp16 *p) { - // CHECK: %[[GE:.*]] = fcmp oge float %[[F:.*]], -1.28{{0*}}e+02 - // CHECK: %[[LE:.*]] = fcmp ole float %[[F]], 1.27{{0*}}e+02 + // CHECK: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.29{{0*}}e+02 + // CHECK: %[[LE:.*]] = fcmp olt float %[[F]], 1.28{{0*}}e+02 // CHECK: and i1 %[[GE]], %[[LE]] // CHECK: call void @__ubsan_handle_float_cast_overflow( - // CHECK-TRAP: %[[GE:.*]] = fcmp oge float %[[F:.*]], -1.28{{0*}}e+02 - // CHECK-TRAP: %[[LE:.*]] = fcmp ole float %[[F]], 1.27{{0*}}e+02 + // CHECK-TRAP: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.29{{0*}}e+02 + // CHECK-TRAP: %[[LE:.*]] = fcmp olt float %[[F]], 1.28{{0*}}e+02 // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]] // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]