diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index cd42585f9ec3..4b18e78e921a 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -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(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(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; diff --git a/clang/test/CodeGen/catch-undef-behavior.c b/clang/test/CodeGen/catch-undef-behavior.c index e8b5cbcd56f1..a90206e46c49 100644 --- a/clang/test/CodeGen/catch-undef-behavior.c +++ b/clang/test/CodeGen/catch-undef-behavior.c @@ -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; +}