зеркало из https://github.com/microsoft/clang-1.git
UBSan: Don't diagnose inf/nan conversions between floating-point types. It's far from clear whether these have undefined behavior, and these checks are helping no-one. Keep the double->float overflow warnings, though, since those are useful in practice, even though it's unclear whether such operations have defined behavior.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178194 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
87d2a37bde
Коммит
508764518d
|
@ -583,19 +583,17 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
|
|||
Check = Builder.CreateAnd(GE, LE);
|
||||
}
|
||||
} 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 (after truncation to an integer for float-to-integer).
|
||||
const llvm::fltSemantics &SrcSema =
|
||||
CGF.getContext().getFloatTypeSemantics(OrigSrcType);
|
||||
APFloat MaxSrc(SrcSema, APFloat::uninitialized);
|
||||
APFloat MinSrc(SrcSema, APFloat::uninitialized);
|
||||
|
||||
if (isa<llvm::IntegerType>(DstTy)) {
|
||||
// Floating-point to integer. This has undefined behavior if the source is
|
||||
// +-Inf, NaN, or doesn't fit into the destination type (after truncation
|
||||
// to an integer).
|
||||
unsigned Width = CGF.getContext().getIntWidth(DstType);
|
||||
bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType();
|
||||
|
||||
APSInt Min = APSInt::getMinValue(Width, Unsigned);
|
||||
APFloat MinSrc(SrcSema, APFloat::uninitialized);
|
||||
if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) &
|
||||
APFloat::opOverflow)
|
||||
// Don't need an overflow check for lower bound. Just check for
|
||||
|
@ -607,6 +605,7 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
|
|||
MinSrc.subtract(APFloat(SrcSema, 1), APFloat::rmTowardNegative);
|
||||
|
||||
APSInt Max = APSInt::getMaxValue(Width, Unsigned);
|
||||
APFloat MaxSrc(SrcSema, APFloat::uninitialized);
|
||||
if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) &
|
||||
APFloat::opOverflow)
|
||||
// Don't need an overflow check for upper bound. Just check for
|
||||
|
@ -616,21 +615,6 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
|
|||
// 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);
|
||||
bool IsInexact;
|
||||
|
||||
MinSrc = APFloat::getLargest(DstSema, true);
|
||||
if (MinSrc.convert(SrcSema, APFloat::rmTowardZero, &IsInexact) &
|
||||
APFloat::opOverflow)
|
||||
MinSrc = APFloat::getLargest(SrcSema, true);
|
||||
|
||||
MaxSrc = APFloat::getLargest(DstSema, false);
|
||||
if (MaxSrc.convert(SrcSema, APFloat::rmTowardZero, &IsInexact) &
|
||||
APFloat::opOverflow)
|
||||
MaxSrc = APFloat::getLargest(SrcSema, false);
|
||||
}
|
||||
|
||||
// If we're converting from __half, convert the range to float to match
|
||||
// the type of src.
|
||||
|
@ -642,18 +626,49 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
|
|||
MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
|
||||
}
|
||||
|
||||
if (isa<llvm::IntegerType>(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 {
|
||||
// FIXME: Maybe split this sanitizer out from float-cast-overflow.
|
||||
//
|
||||
// Floating-point to floating-point. This has undefined behavior if the
|
||||
// source is not in the range of representable values of the destination
|
||||
// type. The C and C++ standards are spectacularly unclear here. We
|
||||
// diagnose finite out-of-range conversions, but allow infinities and NaNs
|
||||
// to convert to the corresponding value in the smaller type.
|
||||
//
|
||||
// C11 Annex F gives all such conversions defined behavior for IEC 60559
|
||||
// conforming implementations. Unfortunately, LLVM's fptrunc instruction
|
||||
// does not.
|
||||
|
||||
// Converting from a lower rank to a higher rank can never have
|
||||
// undefined behavior, since higher-rank types must have a superset
|
||||
// of values of lower-rank types.
|
||||
if (CGF.getContext().getFloatingTypeOrder(OrigSrcType, DstType) != 1)
|
||||
return;
|
||||
|
||||
assert(!OrigSrcType->isHalfType() &&
|
||||
"should not check conversion from __half, it has the lowest rank");
|
||||
|
||||
const llvm::fltSemantics &DstSema =
|
||||
CGF.getContext().getFloatTypeSemantics(DstType);
|
||||
APFloat MinBad = APFloat::getLargest(DstSema, false);
|
||||
APFloat MaxBad = APFloat::getInf(DstSema, false);
|
||||
|
||||
bool IsInexact;
|
||||
MinBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact);
|
||||
MaxBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact);
|
||||
|
||||
Value *AbsSrc = CGF.EmitNounwindRuntimeCall(
|
||||
CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Src->getType()), Src);
|
||||
llvm::Value *GE =
|
||||
Builder.CreateFCmpOGE(Src, llvm::ConstantFP::get(VMContext, MinSrc));
|
||||
Builder.CreateFCmpOGT(AbsSrc, llvm::ConstantFP::get(VMContext, MinBad));
|
||||
llvm::Value *LE =
|
||||
Builder.CreateFCmpOLE(Src, llvm::ConstantFP::get(VMContext, MaxSrc));
|
||||
Check = Builder.CreateAnd(GE, LE);
|
||||
Builder.CreateFCmpOLT(AbsSrc, llvm::ConstantFP::get(VMContext, MaxBad));
|
||||
Check = Builder.CreateNot(Builder.CreateAnd(GE, LE));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -364,14 +364,17 @@ signed char fp16_char_overflow(__fp16 *p) {
|
|||
// CHECK: @float_float_overflow
|
||||
// CHECK-TRAP: @float_float_overflow
|
||||
float float_float_overflow(double f) {
|
||||
// CHECK: %[[GE:.*]] = fcmp oge double %[[F:.*]], 0xC7EFFFFFE0000000
|
||||
// CHECK: %[[LE:.*]] = fcmp ole double %[[F]], 0x47EFFFFFE0000000
|
||||
// CHECK: %[[F:.*]] = call double @llvm.fabs.f64(
|
||||
// CHECK: %[[GE:.*]] = fcmp ogt double %[[F]], 0x47EFFFFFE0000000
|
||||
// CHECK: %[[LE:.*]] = fcmp olt double %[[F]], 0x7FF0000000000000
|
||||
// CHECK: and i1 %[[GE]], %[[LE]]
|
||||
// CHECK: call void @__ubsan_handle_float_cast_overflow(
|
||||
|
||||
// CHECK-TRAP: %[[GE:.*]] = fcmp oge double %[[F:.*]], 0xC7EFFFFFE0000000
|
||||
// CHECK-TRAP: %[[LE:.*]] = fcmp ole double %[[F]], 0x47EFFFFFE0000000
|
||||
// CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
|
||||
// CHECK-TRAP: %[[F:.*]] = call double @llvm.fabs.f64(
|
||||
// CHECK-TRAP: %[[GE:.*]] = fcmp ogt double %[[F]], 0x47EFFFFFE0000000
|
||||
// CHECK-TRAP: %[[LE:.*]] = fcmp olt double %[[F]], 0x7FF0000000000000
|
||||
// CHECK-TRAP: %[[OUTOFBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
|
||||
// CHECK-TRAP: %[[INBOUNDS:.*]] = xor i1 %[[OUTOFBOUNDS]], true
|
||||
// CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
|
||||
|
||||
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
|
||||
|
|
Загрузка…
Ссылка в новой задаче