forked from OSchip/llvm-project
-fcatch-undefined-behavior: Trap undefined behavior due to conversions to or
from a floating-point type where the source value is not in the range of representable values of the destination type. llvm-svn: 165843
This commit is contained in:
parent
be4008472d
commit
f9a1e4ab7d
|
@ -102,6 +102,12 @@ public:
|
|||
/// boolean (i1) truth value. This is equivalent to "Val != 0".
|
||||
Value *EmitConversionToBool(Value *Src, QualType DstTy);
|
||||
|
||||
/// \brief Emit a check that a conversion to or from a floating-point type
|
||||
/// does not overflow.
|
||||
void EmitFloatConversionCheck(Value *OrigSrc, QualType OrigSrcType,
|
||||
Value *Src, QualType SrcType,
|
||||
QualType DstType, llvm::Type *DstTy);
|
||||
|
||||
/// EmitScalarConversion - Emit a conversion from the specified type to the
|
||||
/// specified destination type, both of which are LLVM scalar types.
|
||||
Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy);
|
||||
|
@ -538,6 +544,110 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) {
|
|||
return EmitPointerToBoolConversion(Src);
|
||||
}
|
||||
|
||||
void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
|
||||
QualType OrigSrcType,
|
||||
Value *Src, QualType SrcType,
|
||||
QualType DstType,
|
||||
llvm::Type *DstTy) {
|
||||
using llvm::APFloat;
|
||||
using llvm::APSInt;
|
||||
|
||||
llvm::Type *SrcTy = Src->getType();
|
||||
|
||||
llvm::Value *Check = 0;
|
||||
if (llvm::IntegerType *IntTy = dyn_cast<llvm::IntegerType>(SrcTy)) {
|
||||
// Integer to floating-point. This can fail for unsigned short -> __half
|
||||
// or unsigned __int128 -> float.
|
||||
assert(DstType->isFloatingType());
|
||||
bool SrcIsUnsigned = OrigSrcType->isUnsignedIntegerOrEnumerationType();
|
||||
|
||||
APFloat LargestFloat =
|
||||
APFloat::getLargest(CGF.getContext().getFloatTypeSemantics(DstType));
|
||||
APSInt LargestInt(IntTy->getBitWidth(), SrcIsUnsigned);
|
||||
|
||||
bool IsExact;
|
||||
if (LargestFloat.convertToInteger(LargestInt, APFloat::rmTowardZero,
|
||||
&IsExact) != APFloat::opOK)
|
||||
// The range of representable values of this floating point type includes
|
||||
// all values of this integer type. Don't need an overflow check.
|
||||
return;
|
||||
|
||||
llvm::Value *Max = llvm::ConstantInt::get(VMContext, LargestInt);
|
||||
if (SrcIsUnsigned)
|
||||
Check = Builder.CreateICmpULE(Src, Max);
|
||||
else {
|
||||
llvm::Value *Min = llvm::ConstantInt::get(VMContext, -LargestInt);
|
||||
llvm::Value *GE = Builder.CreateICmpSGE(Src, Min);
|
||||
llvm::Value *LE = Builder.CreateICmpSLE(Src, Max);
|
||||
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.
|
||||
const llvm::fltSemantics &SrcSema =
|
||||
CGF.getContext().getFloatTypeSemantics(OrigSrcType);
|
||||
APFloat MaxSrc(SrcSema, APFloat::uninitialized);
|
||||
APFloat MinSrc(SrcSema, APFloat::uninitialized);
|
||||
|
||||
if (isa<llvm::IntegerType>(DstTy)) {
|
||||
unsigned Width = CGF.getContext().getIntWidth(DstType);
|
||||
bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType();
|
||||
|
||||
APSInt Min = APSInt::getMinValue(Width, Unsigned);
|
||||
if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) &
|
||||
APFloat::opOverflow)
|
||||
// Don't need an overflow check for lower bound. Just check for
|
||||
// -Inf/NaN.
|
||||
MinSrc = APFloat::getLargest(SrcSema, true);
|
||||
|
||||
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);
|
||||
} 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.
|
||||
if (OrigSrcType->isHalfType()) {
|
||||
const llvm::fltSemantics &Sema =
|
||||
CGF.getContext().getFloatTypeSemantics(SrcType);
|
||||
bool IsInexact;
|
||||
MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
|
||||
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);
|
||||
}
|
||||
|
||||
// FIXME: Provide a SourceLocation.
|
||||
llvm::Constant *StaticArgs[] = {
|
||||
CGF.EmitCheckTypeDescriptor(OrigSrcType),
|
||||
CGF.EmitCheckTypeDescriptor(DstType)
|
||||
};
|
||||
CGF.EmitCheck(Check, "float_cast_overflow", StaticArgs, OrigSrc);
|
||||
}
|
||||
|
||||
/// EmitScalarConversion - Emit a conversion from the specified type to the
|
||||
/// specified destination type, both of which are LLVM scalar types.
|
||||
Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
|
||||
|
@ -548,6 +658,8 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
|
|||
|
||||
if (DstType->isVoidType()) return 0;
|
||||
|
||||
llvm::Value *OrigSrc = Src;
|
||||
QualType OrigSrcType = SrcType;
|
||||
llvm::Type *SrcTy = Src->getType();
|
||||
|
||||
// Floating casts might be a bit special: if we're doing casts to / from half
|
||||
|
@ -621,6 +733,12 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
|
|||
Value *Res = NULL;
|
||||
llvm::Type *ResTy = DstTy;
|
||||
|
||||
// An overflowing conversion has undefined behavior if either the source type
|
||||
// or the destination type is a floating-point type.
|
||||
if (CGF.CatchUndefined &&
|
||||
(OrigSrcType->isFloatingType() || DstType->isFloatingType()))
|
||||
EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType, DstTy);
|
||||
|
||||
// Cast to half via float
|
||||
if (DstType->isHalfType())
|
||||
DstTy = CGF.FloatTy;
|
||||
|
|
|
@ -141,3 +141,62 @@ void vla_bound(int n) {
|
|||
#line 900
|
||||
int arr[n * 3];
|
||||
}
|
||||
|
||||
// CHECK: @int_float_no_overflow
|
||||
float int_float_no_overflow(__int128 n) {
|
||||
// CHECK-NOT: call void @__ubsan_handle
|
||||
return n;
|
||||
}
|
||||
|
||||
// CHECK: @int_float_overflow
|
||||
float int_float_overflow(unsigned __int128 n) {
|
||||
// This is 2**104. FLT_MAX is 2**128 - 2**104.
|
||||
// CHECK: icmp ule i128 %{{.*}}, -20282409603651670423947251286016
|
||||
// CHECK: call void @__ubsan_handle_float_cast_overflow(
|
||||
return n;
|
||||
}
|
||||
|
||||
// CHECK: @int_fp16_overflow
|
||||
void int_fp16_overflow(int n, __fp16 *p) {
|
||||
// CHECK: %[[GE:.*]] = icmp sge i32 %{{.*}}, -65504
|
||||
// CHECK: %[[LE:.*]] = icmp sle i32 %{{.*}}, 65504
|
||||
// CHECK: and i1 %[[GE]], %[[LE]]
|
||||
// CHECK: call void @__ubsan_handle_float_cast_overflow(
|
||||
*p = n;
|
||||
}
|
||||
|
||||
// CHECK: @float_int_overflow
|
||||
int float_int_overflow(float f) {
|
||||
// CHECK: %[[GE:.*]] = fcmp oge float %[[F:.*]], 0xC1E0000000000000
|
||||
// CHECK: %[[LE:.*]] = fcmp ole float %[[F]], 0x41DFFFFFE0000000
|
||||
// CHECK: and i1 %[[GE]], %[[LE]]
|
||||
// CHECK: call void @__ubsan_handle_float_cast_overflow(
|
||||
return f;
|
||||
}
|
||||
|
||||
// CHECK: @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: and i1 %[[GE]], %[[LE]]
|
||||
// CHECK: call void @__ubsan_handle_float_cast_overflow(
|
||||
return f;
|
||||
}
|
||||
|
||||
// CHECK: @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: and i1 %[[GE]], %[[LE]]
|
||||
// CHECK: call void @__ubsan_handle_float_cast_overflow(
|
||||
return *p;
|
||||
}
|
||||
|
||||
// CHECK: @float_float_overflow
|
||||
float float_float_overflow(double f) {
|
||||
// CHECK: %[[GE:.*]] = fcmp oge double %[[F:.*]], 0xC7EFFFFFE0000000
|
||||
// CHECK: %[[LE:.*]] = fcmp ole double %[[F]], 0x47EFFFFFE0000000
|
||||
// CHECK: and i1 %[[GE]], %[[LE]]
|
||||
// CHECK: call void @__ubsan_handle_float_cast_overflow(
|
||||
return f;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue