Patchwork Implement -fsanitize=float-cast-overflow (take 2)

login
register
mail settings
Submitter Marek Polacek
Date May 21, 2014, 12:51 p.m.
Message ID <20140521125100.GB5135@redhat.com>
Download mbox | patch
Permalink /patch/351170/
State New
Headers show

Comments

Marek Polacek - May 21, 2014, 12:51 p.m.
On Tue, May 20, 2014 at 09:50:10PM +0000, Joseph S. Myers wrote:
> On Tue, 20 May 2014, Marek Polacek wrote:
> 
> > * is missing tests for long doubles/-mlong-double-128,
> 
> Also missing tests for float - as far as I can see, only double is tested.  
> Ideally all of float, double, long double, __float128 (where supported), 
> __float80 (where supported) would be tested (the functionality supported 
> for __fp16 (ARM) is a bit more restricted) - hopefully using some shared 
> macros to avoid too much duplication between tests.
 
Ok, I've added some tests for float, long double, __float128 and
__float80.  A snag was in __float128 type: libubsan supposedly can't
handle __float128 values and prints "0".  libubsan also can't handle
__float80 types with -m32 it seems.
Common macros moved to float-cast.h.

> > * doesn't instrument _Decimal to integer conversions yet.
> 
> So the code
> 
> > +  else if (REAL_MODE_FORMAT (mode)->b == 10)
> > +    {
> > +      /* For _Decimal128 up to 34 decimal digits, - sign,
> > +	 dot, e, exponent.  */
> 
> isn't actually being used yet?

Yes.  I suspect adding support for _Decimal* shouldn't be hard,
what's needed is to find the place where the conversion from _Decimal
to integer is taking place and add similar code as is in convert.c.
Jakub says he's writing another testcase that tests various type
combination conversions and max/min values - so we'll get even more
coverage.

I tested the following with -m32/-m64 on x86_64 and ppc64.

2014-05-21  Marek Polacek  <polacek@redhat.com>
	    Jakub Jelinek  <jakub@redhat.com>

	* builtins.def: Change SANITIZE_FLOAT_DIVIDE to SANITIZE_NONDEFAULT.
	* gcc.c (sanitize_spec_function): Likewise.
	* convert.c (convert_to_integer): Include "ubsan.h".  Add floating-point
	to integer instrumentation.
	* doc/invoke.texi: Document -fsanitize=float-cast-overflow.
	* flag-types.h (enum sanitize_code): Add SANITIZE_FLOAT_CAST and
	SANITIZE_NONDEFAULT.
	* opts.c (common_handle_option): Handle -fsanitize=float-cast-overflow.
	* sanitizer.def (BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW,
	BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW_ABORT): Add.
	* ubsan.c: Include "realmpfr.h" and "dfp.h".
	(get_ubsan_type_info_for_type): Handle REAL_TYPEs.
	(ubsan_instrument_float_cast): New function.
	* ubsan.h (ubsan_instrument_float_cast): Declare.

	* c-c++-common/ubsan/float-cast-overflow-1.c: New test.
	* c-c++-common/ubsan/float-cast-overflow-2.c: New test.
	* c-c++-common/ubsan/float-cast-overflow-3.c: New test.
	* c-c++-common/ubsan/float-cast-overflow-4.c: New test.
	* c-c++-common/ubsan/float-cast-overflow-5.c: New test.
	* c-c++-common/ubsan/float-cast-overflow-6.c: New test.
	* c-c++-common/ubsan/float-cast.h: New test.
	* g++.dg/ubsan/float-cast-overflow-bf.C: New test.
	* gcc.dg/ubsan/float-cast-overflow-bf.c: New test.

	Marek
Jakub Jelinek - May 21, 2014, 2:46 p.m.
On Wed, May 21, 2014 at 02:51:00PM +0200, Marek Polacek wrote:
> On Tue, May 20, 2014 at 09:50:10PM +0000, Joseph S. Myers wrote:
> > On Tue, 20 May 2014, Marek Polacek wrote:
> > 
> > > * is missing tests for long doubles/-mlong-double-128,
> > 
> > Also missing tests for float - as far as I can see, only double is tested.  
> > Ideally all of float, double, long double, __float128 (where supported), 
> > __float80 (where supported) would be tested (the functionality supported 
> > for __fp16 (ARM) is a bit more restricted) - hopefully using some shared 
> > macros to avoid too much duplication between tests.
>  
> Ok, I've added some tests for float, long double, __float128 and
> __float80.  A snag was in __float128 type: libubsan supposedly can't
> handle __float128 values and prints "0".  libubsan also can't handle
> __float80 types with -m32 it seems.
> Common macros moved to float-cast.h.

Clearly libubsan doesn't support _Decimal* either, so I guess for now
we should just avoid emitting any __ubsan_* diagnostics for any of the
__float{80,128} or _Decimal{32,64,128} types for now, and work with upstream
to add support for that (given the problematic design where a type
is identified only by kind and bitsize, I guess for _Decimal* we need to use
a different (new) kind, not sure what can be done about __float{80,128},
as libubsan treats both bitsize 80 and 128 as long double.

Note that libstdc++ doesn't support conversion of _Decimal{32,64,128}
nor std::decimal::decimal{32,64,128} to strings, and not sure if libubsan
would like to be linked against something that rarely used as libdecnumber.
So, I guess at least for now, we should have a way to tell libubsan
about those types (both decimal and __float{80,128}, but if libubsan
can't easily print those values into strings, it should just print
<unprintable value> or something similar for now.

> Yes.  I suspect adding support for _Decimal* shouldn't be hard,
> what's needed is to find the place where the conversion from _Decimal
> to integer is taking place and add similar code as is in convert.c.
> Jakub says he's writing another testcase that tests various type
> combination conversions and max/min values - so we'll get even more
> coverage.

Here is a testcase that (IMHO, not tested with your patch) should
test various boundary cases that shouldn't result in undefined behavior.
I've tried to keep it portable across various architectures, assumes
primarily two's complement and (likely) only supports binary and decimal
floating point formats.
Seems _Decimal{32,64,128} is not convertible
to/from int128 right now, so that is disabled in the test for now.

	Jakub
/* { dg-do run } */
/* { dg-options "-fsanitize=float-cast-overflow -fno-sanitize-recover" } */
/* FIXME: When _DecimalXX <-> {signed, unsigned} __int128 conversions are
   supported, -DBROKEN_DECIMAL_INT128 can be removed.  */
/* { dg-additional-options "-DUSE_DFP -DBROKEN_DECIMAL_INT128" { target dfp } } */

#define CVTFN(type1, type2) \
__attribute__((noinline)) type1	\
cvt_##type1##_##type2 (type2 x)	\
{				\
  return x;			\
}

typedef signed char sc;
#define sc_MIN (-__SCHAR_MAX__ - 1)
#define sc_MAX __SCHAR_MAX__
typedef unsigned char uc;
#define uc_MIN 0
#define uc_MAX (2U * __SCHAR_MAX__ + 1U)
typedef char c;
#define c_MIN ((((char) -1) > (char) 0) ? uc_MIN : sc_MIN)
#define c_MAX ((((char) -1) > (char) 0) ? uc_MAX : sc_MAX)
typedef signed short ss;
#define ss_MIN (-__SHRT_MAX__ - 1)
#define ss_MAX __SHRT_MAX__
typedef unsigned short us;
#define us_MIN 0
#define us_MAX (2U * __SHRT_MAX__ + 1U)
typedef signed int si;
#define si_MIN (-__INT_MAX__ - 1)
#define si_MAX __INT_MAX__
typedef unsigned int ui;
#define ui_MIN 0
#define ui_MAX (2U * __INT_MAX__ + 1U)
typedef signed long sl;
#define sl_MIN (-__LONG_MAX__ - 1L)
#define sl_MAX __LONG_MAX__
typedef unsigned long ul;
#define ul_MIN 0L
#define ul_MAX (2UL * __LONG_MAX__ + 1UL)
typedef signed long long sll;
#define sll_MIN (-__LONG_LONG_MAX__ - 1LL)
#define sll_MAX __LONG_LONG_MAX__
typedef unsigned long long ull;
#define ull_MIN 0LL
#define ull_MAX (2ULL * __LONG_LONG_MAX__ + 1ULL)
#ifdef __SIZEOF_INT128__
typedef signed __int128 si128;
# define si128_MAX \
  ((signed __int128) ((((unsigned __int128) 1) \
		       << (__CHAR_BIT__ * __SIZEOF_INT128__ - 1)) - 1))
# define si128_MIN (-si128_MAX - 1)
typedef unsigned __int128 ui128;
#define ui128_MIN ((unsigned __int128) 0)
#define ui128_MAX (((unsigned __int128) 2) * si128_MAX + 1)
#endif

#ifdef __SIZEOF_INT128__
# define CVTS128(type2) CVTFN (si128, type2) CVTFN (ui128, type2)
#else
# define CVTS128(type2)
#endif

#define CVTS(type2) \
  CVTFN (sc, type2) CVTFN (c, type2) CVTFN (uc, type2)	\
  CVTFN (ss, type2) CVTFN (us, type2)			\
  CVTFN (si, type2) CVTFN (ui, type2)			\
  CVTFN (sl, type2) CVTFN (ul, type2)			\
  CVTFN (sll, type2) CVTFN (ull, type2)			\
  CVTS128 (type2)

#ifdef __SIZEOF_INT128__
# define TWO ((unsigned __int128) 2)
# define M1U ((unsigned __int128) -1)
# define MAXS (__CHAR_BIT__ * __SIZEOF_INT128__)
# define MAXT unsigned __int128
#else
# define TWO 2ULL
# define M1U -1ULL
# define MAXS (__CHAR_BIT__ * __SIZEOF_LONG_LONG__)
# define MAXT unsigned long long
#endif

typedef float f;
#define f_RADIX 2
#define f_MANT_DIG __FLT_MANT_DIG__
#define f_MAX ((TWO << (f_MANT_DIG - 1)) - 1)
typedef double d;
#define d_RADIX 2
#define d_MANT_DIG __DBL_MANT_DIG__
#define d_MAX ((TWO << (d_MANT_DIG - 1)) - 1)
typedef long double ld;
#define ld_RADIX 2
#define ld_MANT_DIG __LDBL_MANT_DIG__
#define ld_MAX \
  (ld_MANT_DIG > MAXS ? M1U : (TWO << (ld_MANT_DIG > MAXS \
				       ? 0 : ld_MANT_DIG - 1)) - 1)
CVTS (f)
CVTS (d)
CVTS (ld)
#ifdef __SIZEOF_FLOAT80__
typedef __float80 f80;
# define f80_RADIX 2
# define f80_MANT_DIG 64
# define f80_MAX ((TWO << (d_MANT_DIG - 1)) - 1)
CVTS (f80)
#endif
#ifdef __SIZEOF_FLOAT128__
typedef __float128 f128;
# define f128_RADIX 2
# define f128_MANT_DIG 113
# define f128_MAX \
  (f128_MANT_DIG > MAXS ? M1U : (TWO << (f128_MANT_DIG > MAXS \
					 ? 0 : f128_MANT_DIG - 1)) - 1)
CVTS (f128)
#endif
#ifdef USE_DFP
typedef _Decimal32 d32;
# define d32_RADIX 10
# define d32_MANT_DIG __DEC32_MANT_DIG__
# if d32_MANT_DIG == 7
#  define d32_MAX 9999999ULL
# endif
typedef _Decimal64 d64;
# define d64_RADIX 10
# define d64_MANT_DIG __DEC64_MANT_DIG__
# if d64_MANT_DIG == 16
#  define d64_MAX 9999999999999999ULL
# endif
typedef _Decimal128 d128;
# define d128_RADIX 10
# define d128_MANT_DIG __DEC128_MANT_DIG__
# ifdef __SIZEOF_FLOAT128__
#  if d128_MANT_DIG == 34
/* #define d128_MAX 1ed09bead87c0378d8e63ffffffff */
#   define d128_MAX \
  ((((unsigned __int128) 0x1ed09bead87c0) << 64) + 0x378d8e63ffffffffULL)
#  else
#   define d128_MAX M1U
#  endif
# endif
# ifdef BROKEN_DECIMAL_INT128
#  undef CVTS128
#  define CVTS128(type2)
# endif
CVTS (d32)
CVTS (d64)
CVTS (d128)
#endif

extern
#ifdef __cplusplus
"C"
#endif
void abort ();
#define P(n) __builtin_printf ("%d\n", n)

#define TEST(type1, type2) \
  if (cvt_##type1##_##type2 (-0.5f) != 0) abort ();		\
  if (cvt_##type1##_##type2 (0.5f) != 0) abort ();		\
  if (cvt_##type1##_##type2 (-0.75f) != 0) abort ();		\
  if (cvt_##type1##_##type2 (0.75f) != 0) abort ();		\
  if (type1##_MIN)						\
    {								\
      /* For RADIX 2 type1##_MIN should be always */		\
      /* exactly representable in type2.  */			\
      if (type2##_RADIX == 2					\
	  || type1##_MAX <= type2##_MAX)			\
	{							\
	  if (cvt_##type1##_##type2 (type1##_MIN)		\
	      != type1##_MIN) abort ();				\
	  if (cvt_##type1##_##type2 ((type2) -0.75f		\
				     + type1##_MIN)		\
	      != type1##_MIN) abort ();				\
	}							\
      else							\
	{							\
	  type2 min = type1##_MIN;				\
	  /* tem could be below minimum here due to */		\
	  /* rounding.  */					\
	  MAXT add = 1;						\
	  while (add)						\
	    {							\
	      volatile type2 tem = type1##_MIN + (type1) add;	\
	      if (tem != min)					\
		break;						\
	      MAXT newadd = add * type2##_RADIX;		\
	      if (newadd < add || newadd > type1##_MAX)		\
		add = 0;					\
	      else						\
		add = newadd;					\
	    }							\
	  if (add)						\
	    {							\
	      MAXT newadd					\
		= (-(type1##_MIN + (type1) add)) % add;		\
	      volatile type2 tem = type1##_MIN + (type1) newadd;\
	      volatile type2 tem2 = type1##_MIN + (type1) add;	\
	      if (tem == tem2)					\
		add = newadd;					\
	      else						\
		{						\
		  newadd += add;				\
		  if (newadd < add || newadd > type1##_MAX)	\
		    add = 0;					\
		  else						\
		    {						\
		      tem = type1##_MIN + (type1) newadd;	\
		      if (tem == tem2)				\
			add = newadd;				\
		      else					\
			add = 0;				\
		    }						\
		}						\
	    }							\
	  if (add						\
	      && cvt_##type1##_##type2 (type1##_MIN		\
					+ (type1) add)		\
		 != type1##_MIN + (type1) add) abort ();	\
	}							\
    }								\
  if (type1##_MAX <= type2##_MAX)				\
    {								\
      if (cvt_##type1##_##type2 (type1##_MAX) != type1##_MAX)	\
	abort ();						\
      volatile type2 tem = ((type2) 0.75f) + type1##_MAX;	\
      volatile type2 tem2 = ((type2) 1.0f) + type1##_MAX;	\
      if (tem < tem2						\
	  && cvt_##type1##_##type2 ((type2) 0.75f + type1##_MAX)\
	     != type1##_MAX) abort ();				\
    }								\
  else								\
    {								\
      type2 max = type1##_MAX;					\
      /* tem could be above maximum here due to rounding.  */	\
      MAXT sub = 1;						\
      while (sub)						\
	{							\
	  volatile type2 tem = type1##_MAX - sub;		\
	  if (tem != max)					\
	    break;						\
	  MAXT newsub = sub * type2##_RADIX;			\
	  if (newsub < sub || newsub > type1##_MAX)		\
	    sub = 0;						\
	  else							\
	    sub = newsub;					\
	}							\
      if (sub)							\
	{							\
	  MAXT newsub = ((type1##_MAX - sub) % sub);		\
	  volatile type2 tem = type1##_MAX - newsub;		\
	  volatile type2 tem2 = type1##_MAX - sub;		\
	  if (tem == tem2)					\
	    sub = newsub;					\
	  else							\
	    {							\
	      newsub += sub;					\
	      if (newsub < sub || newsub > type1##_MAX)		\
		sub = 0;					\
	      else						\
		{						\
		  tem = type1##_MAX - newsub;			\
		  if (tem == tem2)				\
		    sub = newsub;				\
		  else						\
		    sub = 0;					\
		}						\
	    }							\
	}							\
      if (sub							\
	  && cvt_##type1##_##type2 (type1##_MAX - sub)		\
	     != type1##_MAX - sub) abort ();			\
    }


#ifdef __SIZEOF_INT128__
# define TESTS128(type2) TEST (si128, type2) TEST (ui128, type2)
#else
# define TESTS128(type2)
#endif

#define TESTS(type2) \
  TEST (sc, type2) TEST (c, type2) TEST (uc, type2)	\
  TEST (ss, type2) TEST (us, type2)			\
  TEST (si, type2) TEST (ui, type2)			\
  TEST (sl, type2) TEST (ul, type2)			\
  TEST (sll, type2) TEST (ull, type2)			\
  TESTS128 (type2)

int
main ()
{
  TESTS (f)
  TESTS (d)
  TESTS (ld)
#ifdef f80_MAX
  TESTS (f80)
#endif
#ifdef f128_MAX
  TESTS (f128)
#endif
#ifdef BROKEN_DECIMAL_INT128
# undef TESTS128
# define TESTS128(type2)
# undef TWO
# undef M1U
# undef MAXS
# undef MAXT
# define TWO 2ULL
# define M1U -1ULL
# define MAXS (__CHAR_BIT__ * __SIZEOF_LONG_LONG__)
# define MAXT unsigned long long
#endif
#ifdef d32_MAX
  TESTS (d32)
#endif
#ifdef d64_MAX
  TESTS (d64)
#endif
#ifdef d128_MAX
  TESTS (d128)
#endif
  return 0;
}
Joseph S. Myers - May 21, 2014, 5:49 p.m.
On Wed, 21 May 2014, Marek Polacek wrote:

> On Tue, May 20, 2014 at 09:50:10PM +0000, Joseph S. Myers wrote:
> > On Tue, 20 May 2014, Marek Polacek wrote:
> > 
> > > * is missing tests for long doubles/-mlong-double-128,
> > 
> > Also missing tests for float - as far as I can see, only double is tested.  
> > Ideally all of float, double, long double, __float128 (where supported), 
> > __float80 (where supported) would be tested (the functionality supported 
> > for __fp16 (ARM) is a bit more restricted) - hopefully using some shared 
> > macros to avoid too much duplication between tests.
>  
> Ok, I've added some tests for float, long double, __float128 and
> __float80.  A snag was in __float128 type: libubsan supposedly can't
> handle __float128 values and prints "0".  libubsan also can't handle
> __float80 types with -m32 it seems.

__float80 is normally the same as long double (in terms of representation 
anyway, whether or not it's a distinct type).  On x86, it's only 
-mlong-double-128 (64-bit Bionic) that means they are different; on IA64 
it's HP-UX where they are different.  (On x86_64, typically __float80 and 
__float128 will both have the same size, although different 
representations.)

It looks to me from i386.c like __float80 is just a built-in typedef for 
long double if long double is XFmode, but __float128 is always distinct 
(always created with a separate make_node (REAL_TYPE) call) (although for 
IA64 HP-UX, __float128 looks like it is a typedef - and for IA64 in 
general, it looks like __float80 is always distinct).  I don't know if 
cleanup in this area is worthwhile at this point - FWIW, draft TS 18661-3, 
soon to go to PDTS ballot, makes its types such as _Float64x and _Float128 
all distinct from each other and from the standard types such as long 
double.

I'd hope that if a type has the same representation as one of the standard 
types, it could be handled the same in libubsan without needing any 
special support there (so you'd need new support for __float128, but not 
for __float80 when that has the same representation as long double) - just 
as libgcc just needs one set of XFmode functions and one set of TFmode 
functions even if there are multiple types with those modes.

Patch

diff --git gcc/builtins.def gcc/builtins.def
index d400ecb..cd823a3 100644
--- gcc/builtins.def
+++ gcc/builtins.def
@@ -176,7 +176,7 @@  along with GCC; see the file COPYING3.  If not see
   DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,    \
 	       true, true, true, ATTRS, true, \
 	      (flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \
-				| SANITIZE_UNDEFINED | SANITIZE_FLOAT_DIVIDE)))
+				| SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT)))
 
 #undef DEF_CILKPLUS_BUILTIN
 #define DEF_CILKPLUS_BUILTIN(ENUM, NAME, TYPE, ATTRS)  \
diff --git gcc/convert.c gcc/convert.c
index 91c1da2..b8f3671 100644
--- gcc/convert.c
+++ gcc/convert.c
@@ -32,6 +32,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #include "target.h"
 #include "langhooks.h"
+#include "ubsan.h"
 
 /* Convert EXPR to some pointer or reference type TYPE.
    EXPR must be pointer, reference, integer, enumeral, or literal zero;
@@ -394,6 +395,7 @@  convert_to_integer (tree type, tree expr)
   tree intype = TREE_TYPE (expr);
   unsigned int inprec = element_precision (intype);
   unsigned int outprec = element_precision (type);
+  location_t loc = EXPR_LOCATION (expr);
 
   /* An INTEGER_TYPE cannot be incomplete, but an ENUMERAL_TYPE can
      be.  Consider `enum E = { a, b = (enum E) 3 };'.  */
@@ -844,7 +846,17 @@  convert_to_integer (tree type, tree expr)
       return build1 (CONVERT_EXPR, type, expr);
 
     case REAL_TYPE:
-      return build1 (FIX_TRUNC_EXPR, type, expr);
+      if (flag_sanitize & SANITIZE_FLOAT_CAST)
+	{
+	  expr = save_expr (expr);
+	  tree check = ubsan_instrument_float_cast (loc, type, expr);
+	  expr = build1 (FIX_TRUNC_EXPR, type, expr);
+	  if (check == NULL)
+	    return expr;
+	  return fold_build2 (COMPOUND_EXPR, TREE_TYPE (expr), check, expr);
+	}
+      else
+	return build1 (FIX_TRUNC_EXPR, type, expr);
 
     case FIXED_POINT_TYPE:
       return build1 (FIXED_CONVERT_EXPR, type, expr);
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index 5b1b0f1..659c265 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -5427,6 +5427,13 @@  Detect floating-point division by zero.  Unlike other similar options,
 @option{-fsanitize=undefined}, since floating-point division by zero can
 be a legitimate way of obtaining infinities and NaNs.
 
+@item -fsanitize=float-cast-overflow
+@opindex fsanitize=float-cast-overflow
+
+This option enables floating-point type to integer conversion checking.
+We check that the result of the conversion does not overflow.
+This option does not work well with @code{FE_INVALID} exceptions enabled.
+
 @item -fsanitize-recover
 @opindex fsanitize-recover
 By default @option{-fsanitize=undefined} sanitization (and its suboptions
diff --git gcc/flag-types.h gcc/flag-types.h
index caf4039..ed00046 100644
--- gcc/flag-types.h
+++ gcc/flag-types.h
@@ -229,9 +229,11 @@  enum sanitize_code {
   SANITIZE_BOOL = 1 << 10,
   SANITIZE_ENUM = 1 << 11,
   SANITIZE_FLOAT_DIVIDE = 1 << 12,
+  SANITIZE_FLOAT_CAST = 1 << 13,
   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
 		       | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
-		       | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM
+		       | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM,
+  SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
 };
 
 /* flag_vtable_verify initialization levels. */
diff --git gcc/gcc.c gcc/gcc.c
index 7bea6d7..9ac18e6 100644
--- gcc/gcc.c
+++ gcc/gcc.c
@@ -8170,7 +8170,7 @@  sanitize_spec_function (int argc, const char **argv)
   if (strcmp (argv[0], "thread") == 0)
     return (flag_sanitize & SANITIZE_THREAD) ? "" : NULL;
   if (strcmp (argv[0], "undefined") == 0)
-    return ((flag_sanitize & (SANITIZE_UNDEFINED | SANITIZE_FLOAT_DIVIDE))
+    return ((flag_sanitize & (SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT))
 	    && !flag_sanitize_undefined_trap_on_error) ? "" : NULL;
   if (strcmp (argv[0], "leak") == 0)
     return ((flag_sanitize
diff --git gcc/opts.c gcc/opts.c
index 5f4b2e3..2f4f913 100644
--- gcc/opts.c
+++ gcc/opts.c
@@ -1463,6 +1463,8 @@  common_handle_option (struct gcc_options *opts,
 	      { "enum", SANITIZE_ENUM, sizeof "enum" - 1 },
 	      { "float-divide-by-zero", SANITIZE_FLOAT_DIVIDE,
 		sizeof "float-divide-by-zero" - 1 },
+	      { "float-cast-overflow", SANITIZE_FLOAT_CAST,
+		sizeof "float-cast-overflow" - 1 },
 	      { NULL, 0, 0 }
 	    };
 	    const char *comma;
diff --git gcc/sanitizer.def gcc/sanitizer.def
index 6184b5a..a2f7ff0 100644
--- gcc/sanitizer.def
+++ gcc/sanitizer.def
@@ -371,3 +371,11 @@  DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE_ABORT,
 		      "__ubsan_handle_load_invalid_value_abort",
 		      BT_FN_VOID_PTR_PTR,
 		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW,
+		      "__ubsan_handle_float_cast_overflow",
+		      BT_FN_VOID_PTR_PTR,
+		      ATTR_COLD_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW_ABORT,
+		      "__ubsan_handle_float_cast_overflow_abort",
+		      BT_FN_VOID_PTR_PTR,
+		      ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
diff --git gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-1.c gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-1.c
index e69de29..249731d 100644
--- gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-1.c
+++ gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-1.c
@@ -0,0 +1,204 @@ 
+/* { dg-do run { target { lp64 || ilp32 } } } */
+/* { dg-options "-fsanitize=float-cast-overflow" } */
+/* { dg-additional-options "-msse2 -mfpmath=sse" { target { sse2_runtime && ia32 } } } */
+
+#include <limits.h>
+#include "float-cast.h"
+
+int
+main (void)
+{
+  const double inf = __builtin_inf ();
+  const double nan = __builtin_nan ("");
+  volatile double d;
+
+  volatile signed char sc;
+  d = SCHAR_MIN;
+  CHECK_BOUNDARY (sc, d);
+  d = 0.0;
+  CHECK_BOUNDARY (sc, d);
+  d = SCHAR_MAX;
+  CHECK_BOUNDARY (sc, d);
+  CHECK_NONNUMBERS (sc);
+
+  volatile unsigned char uc;
+  d = UCHAR_MAX;
+  CHECK_BOUNDARY (uc, d);
+  d = 0.0;
+  CHECK_BOUNDARY (uc, d);
+  CHECK_NONNUMBERS (uc);
+
+  volatile short int s;
+  d = SHRT_MIN;
+  CHECK_BOUNDARY (s, d);
+  d = 0.0;
+  CHECK_BOUNDARY (s, d);
+  d = SHRT_MAX;
+  CHECK_BOUNDARY (s, d);
+  CHECK_NONNUMBERS (s);
+
+  volatile unsigned short int us;
+  d = USHRT_MAX;
+  CHECK_BOUNDARY (us, d);
+  d = 0.0;
+  CHECK_BOUNDARY (us, d);
+  CHECK_NONNUMBERS (us);
+
+  volatile int i;
+  d = INT_MIN;
+  CHECK_BOUNDARY (i, d);
+  d = 0.0;
+  CHECK_BOUNDARY (i, d);
+  d = INT_MAX;
+  CHECK_BOUNDARY (i, d);
+  CHECK_NONNUMBERS (i);
+
+  volatile unsigned int u;
+  d = UINT_MAX;
+  CHECK_BOUNDARY (u, d);
+  d = 0.0;
+  CHECK_BOUNDARY (u, d);
+  CHECK_NONNUMBERS (u);
+
+  volatile long l;
+  /* 64-bit vs 32-bit longs matter causes too much of a headache.  */
+  d = 0.0;
+  CHECK_BOUNDARY (l, d);
+  CHECK_NONNUMBERS (l);
+
+  volatile unsigned long ul;
+  d = 0.0;
+  CHECK_BOUNDARY (ul, d);
+  CHECK_NONNUMBERS (ul);
+
+  volatile long long ll;
+  d = LLONG_MIN;
+  CHECK_BOUNDARY (ll, d);
+  d = 0.0;
+  CHECK_BOUNDARY (ll, d);
+  d = LLONG_MAX;
+  CHECK_BOUNDARY (ll, d);
+  CHECK_NONNUMBERS (ll);
+
+  volatile unsigned long long ull;
+  d = ULLONG_MAX;
+  CHECK_BOUNDARY (ull, d);
+  d = 0.0;
+  CHECK_BOUNDARY (ull, d);
+  CHECK_NONNUMBERS (ull);
+
+  return 0;
+}
+
+/* { dg-output "value -133 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -129.5 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 128 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 128.5 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 132 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -nan is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 256 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 256.5 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 260 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -nan is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -32773 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -32769.5 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 32768 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 32768.5 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 32772 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -nan is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 65536 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 65536.5 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 65540 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -nan is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -nan is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -nan is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -nan is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -nan is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -nan is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -nan is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
diff --git gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-2.c gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-2.c
index e69de29..15eacc9 100644
--- gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-2.c
+++ gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-2.c
@@ -0,0 +1,73 @@ 
+/* { dg-do run } */
+/* { dg-require-effective-target int128 } */
+/* { dg-options "-fsanitize=float-cast-overflow" } */
+
+#include "float-cast.h"
+
+int
+main (void)
+{
+  const double inf = __builtin_inf ();
+  const double nan = __builtin_nan ("");
+  volatile double d;
+
+  __int128 i;
+  d = INT128_MIN;
+  CHECK_BOUNDARY (i, d);
+  d = 0.0;
+  CHECK_BOUNDARY (i, d);
+  d = INT128_MAX;
+  CHECK_BOUNDARY (i, d);
+  CHECK_NONNUMBERS (i);
+
+  unsigned __int128 u;
+  d = UINT128_MAX;
+  CHECK_BOUNDARY (u, d);
+  d = 0.0;
+  CHECK_BOUNDARY (u, d);
+  CHECK_NONNUMBERS (u);
+
+  return 0;
+}
+
+/* { dg-output "runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value nan is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value -nan is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value inf is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value -inf is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value -5 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value -1.5 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value nan is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value -nan is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value inf is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: value -inf is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
diff --git gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-3.c gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-3.c
index e69de29..2200e66 100644
--- gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-3.c
+++ gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-3.c
@@ -0,0 +1,40 @@ 
+/* { dg-do run { target { lp64 || ilp32 } } } */
+/* { dg-options "-fsanitize=float-cast-overflow" } */
+
+#include <limits.h>
+#include "float-cast.h"
+
+int
+main (void)
+{
+  volatile float f;
+
+  volatile signed char s;
+  f = SCHAR_MIN;
+  CHECK_BOUNDARY (s, f);
+  f = 0.0;
+  CHECK_BOUNDARY (s, f);
+  f = SCHAR_MAX;
+  CHECK_BOUNDARY (s, f);
+
+  volatile unsigned char u;
+  f = UCHAR_MAX;
+  CHECK_BOUNDARY (u, f);
+  f = 0.0;
+  CHECK_BOUNDARY (u, f);
+
+  return 0;
+}
+
+/* { dg-output "value -133* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -129.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -129 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 128 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 128.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 132 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 256 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 256.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 260 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
diff --git gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-4.c gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-4.c
index e69de29..7704aa9 100644
--- gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-4.c
+++ gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-4.c
@@ -0,0 +1,52 @@ 
+/* { dg-do run { target { lp64 } } } */
+/* { dg-options "-fsanitize=float-cast-overflow" } */
+
+#include <limits.h>
+#include "float-cast.h"
+
+int
+main (void)
+{
+  const long double inf = __builtin_infl ();
+  const long double nan = __builtin_nanl ("");
+  volatile long double ld;
+
+  volatile int i;
+  ld = INT_MIN;
+  CHECK_BOUNDARY (i, ld);
+  ld = 0.0l;
+  CHECK_BOUNDARY (i, ld);
+  ld = INT_MAX;
+  CHECK_BOUNDARY (i, ld);
+  CHECK_NONNUMBERS (i);
+
+  volatile unsigned int u;
+  ld = UINT_MAX;
+  CHECK_BOUNDARY (u, ld);
+  ld = 0.0l;
+  CHECK_BOUNDARY (u, ld);
+  CHECK_NONNUMBERS (u);
+
+  return 0;
+}
+
+/* { dg-output "value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
diff --git gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-5.c gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-5.c
index e69de29..44910ee 100644
--- gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-5.c
+++ gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-5.c
@@ -0,0 +1,40 @@ 
+/* { dg-do run { target i?86-*-* x86_64-*-* ia64-*-* } } */
+/* { dg-options "-fsanitize=float-cast-overflow" } */
+
+#include <limits.h>
+#include "float-cast.h"
+
+int
+main (void)
+{
+  volatile __float128 f;
+
+  volatile signed char s;
+  f = SCHAR_MIN;
+  CHECK_BOUNDARY (s, f);
+  f = 0.0q;
+  CHECK_BOUNDARY (s, f);
+  f = SCHAR_MAX;
+  CHECK_BOUNDARY (s, f);
+
+  volatile unsigned char u;
+  f = UCHAR_MAX;
+  CHECK_BOUNDARY (u, f);
+  f = 0.0q;
+  CHECK_BOUNDARY (u, f);
+
+  return 0;
+}
+
+/* { dg-output "value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
diff --git gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-6.c gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-6.c
index e69de29..f51a2c8 100644
--- gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-6.c
+++ gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-6.c
@@ -0,0 +1,40 @@ 
+/* { dg-do run { target { { x86_64-*-* ia64-*-* } && { ! { ia32 } } } } } */
+/* { dg-options "-fsanitize=float-cast-overflow" } */
+
+#include <limits.h>
+#include "float-cast.h"
+
+int
+main (void)
+{
+  volatile __float80 f;
+
+  volatile signed char s;
+  f = SCHAR_MIN;
+  CHECK_BOUNDARY (s, f);
+  f = 0.0w;
+  CHECK_BOUNDARY (s, f);
+  f = SCHAR_MAX;
+  CHECK_BOUNDARY (s, f);
+
+  volatile unsigned char u;
+  f = UCHAR_MAX;
+  CHECK_BOUNDARY (u, f);
+  f = 0.0w;
+  CHECK_BOUNDARY (u, f);
+
+  return 0;
+}
+
+/* { dg-output "value -133 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -129.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -129 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 128 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 128.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 132 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 256 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 256.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 260 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
diff --git gcc/testsuite/c-c++-common/ubsan/float-cast.h gcc/testsuite/c-c++-common/ubsan/float-cast.h
index e69de29..166da8f 100644
--- gcc/testsuite/c-c++-common/ubsan/float-cast.h
+++ gcc/testsuite/c-c++-common/ubsan/float-cast.h
@@ -0,0 +1,28 @@ 
+/* Various macros for -fsanitize=float-cast-overflow testing.  */
+
+#define INT128_MAX (__int128) (((unsigned __int128) 1 << ((__SIZEOF_INT128__ * __CHAR_BIT__) - 1)) - 1)
+#define INT128_MIN (-INT128_MAX - 1)
+#define UINT128_MAX ((2 * (unsigned __int128) INT128_MAX) + 1)
+
+#define CHECK_BOUNDARY(VAR, VAL)	\
+  (VAR) = (VAL) - 5.0;			\
+  (VAR) = (VAL) - 1.5;			\
+  (VAR) = (VAL) - 1.0;			\
+  (VAR) = (VAL) - 0.75;			\
+  (VAR) = (VAL) - 0.5;			\
+  (VAR) = (VAL) - 0.0000001;		\
+  (VAR) = (VAL) - 0.0;			\
+  (VAR) = (VAL);			\
+  (VAR) = (VAL) + 0.0;			\
+  (VAR) = (VAL) + 0.0000001;		\
+  (VAR) = (VAL) + 0.5;			\
+  (VAR) = (VAL) + 0.75;			\
+  (VAR) = (VAL) + 1.0;			\
+  (VAR) = (VAL) + 1.5;			\
+  (VAR) = (VAL) + 5.0;
+
+#define CHECK_NONNUMBERS(VAR)		\
+  (VAR) = nan;				\
+  (VAR) = -nan;				\
+  (VAR) = inf;				\
+  (VAR) = -inf;
diff --git gcc/testsuite/g++.dg/ubsan/float-cast-overflow-bf.C gcc/testsuite/g++.dg/ubsan/float-cast-overflow-bf.C
index e69de29..d1df76d 100644
--- gcc/testsuite/g++.dg/ubsan/float-cast-overflow-bf.C
+++ gcc/testsuite/g++.dg/ubsan/float-cast-overflow-bf.C
@@ -0,0 +1,62 @@ 
+// { dg-do run { target { int32 } } }
+// { dg-options "-fsanitize=float-cast-overflow" }
+
+#define INT_MAX __INT_MAX__
+#define INT_MIN (-__INT_MAX__ - 1)
+#define UINT_MAX 2 * (unsigned) __INT_MAX__ + 1
+
+struct S
+{
+  int i:1;
+} s;
+
+struct T
+{
+  unsigned int i:1;
+} t;
+
+int
+main (void)
+{
+  volatile double d;
+
+#define CHECK_BOUNDARY(VAR, VAL)        \
+  (VAR) = (VAL) - 1.5;                  \
+  (VAR) = (VAL) - 1.0;                  \
+  (VAR) = (VAL) - 0.75;                  \
+  (VAR) = (VAL) - 0.5;                  \
+  (VAR) = (VAL) - 0.0000001;            \
+  (VAR) = (VAL) - 0.0;                  \
+  (VAR) = (VAL);                        \
+  (VAR) = (VAL) + 0.0;                  \
+  (VAR) = (VAL) + 0.0000001;            \
+  (VAR) = (VAL) + 0.5;                  \
+  (VAR) = (VAL) + 0.75;                  \
+  (VAR) = (VAL) + 1.0;                  \
+  (VAR) = (VAL) + 1.5;
+
+  /* Signed bit-field.  (INT_MIN, INT_MAX) is valid.  */
+  d = INT_MIN;
+  CHECK_BOUNDARY (s.i, d);
+  d = 0.0;
+  CHECK_BOUNDARY (s.i, d);
+  d = INT_MAX;
+  CHECK_BOUNDARY (s.i, d);
+
+  /* Unsigned bit-field.  (0, UINT_MAX) is valid.  */
+  d = UINT_MAX;
+  CHECK_BOUNDARY (t.i, d);
+  d = 0.0;
+  CHECK_BOUNDARY (t.i, d);
+
+  return 0;
+}
+
+/* { dg-output "value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
diff --git gcc/testsuite/gcc.dg/ubsan/float-cast-overflow-bf.c gcc/testsuite/gcc.dg/ubsan/float-cast-overflow-bf.c
index e69de29..298d0d9 100644
--- gcc/testsuite/gcc.dg/ubsan/float-cast-overflow-bf.c
+++ gcc/testsuite/gcc.dg/ubsan/float-cast-overflow-bf.c
@@ -0,0 +1,72 @@ 
+/* { dg-do run } */
+/* { dg-options "-fsanitize=float-cast-overflow" } */
+
+struct
+{
+  int i:1;
+} s;
+
+struct
+{
+  unsigned int i:1;
+} t;
+
+int
+main (void)
+{
+  volatile double d;
+
+#define CHECK_BOUNDARY(VAR, VAL)        \
+  (VAR) = (VAL) - 1.5;                  \
+  (VAR) = (VAL) - 1.0;                  \
+  (VAR) = (VAL) - 0.5;                  \
+  (VAR) = (VAL) - 0.0000001;            \
+  (VAR) = (VAL) - 0.0;                  \
+  (VAR) = (VAL);                        \
+  (VAR) = (VAL) + 0.0;                  \
+  (VAR) = (VAL) + 0.0000001;            \
+  (VAR) = (VAL) + 0.5;                  \
+  (VAR) = (VAL) + 1.0;                  \
+  (VAR) = (VAL) + 1.5;
+
+  /* Signed bit-field.  (-1, 0) is valid.  */
+  d = -1.0;
+  CHECK_BOUNDARY (s.i, d);
+  d = 0.0;
+  CHECK_BOUNDARY (s.i, d);
+  d = 1.0;
+  CHECK_BOUNDARY (s.i, d);
+
+  /* Unsigned bit-field.  (0, 1) is valid.  */
+  d = -1.0;
+  CHECK_BOUNDARY (t.i, d);
+  d = 0.0;
+  CHECK_BOUNDARY (t.i, d);
+  d = 1.0;
+  CHECK_BOUNDARY (t.i, d);
+
+  return 0;
+}
+
+/* { dg-output "value -2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
diff --git gcc/ubsan.c gcc/ubsan.c
index 11461d0..cc5556f 100644
--- gcc/ubsan.c
+++ gcc/ubsan.c
@@ -47,6 +47,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "gimplify-me.h"
 #include "intl.h"
+#include "realmpfr.h"
+#include "dfp.h"
 
 /* Map from a tree to a VAR_DECL tree.  */
 
@@ -267,9 +269,14 @@  static unsigned short
 get_ubsan_type_info_for_type (tree type)
 {
   gcc_assert (TYPE_SIZE (type) && tree_fits_uhwi_p (TYPE_SIZE (type)));
-  int prec = exact_log2 (tree_to_uhwi (TYPE_SIZE (type)));
-  gcc_assert (prec != -1);
-  return (prec << 1) | !TYPE_UNSIGNED (type);
+  if (TREE_CODE (type) == REAL_TYPE)
+    return tree_to_uhwi (TYPE_SIZE (type));
+  else
+    {
+      int prec = exact_log2 (tree_to_uhwi (TYPE_SIZE (type)));
+      gcc_assert (prec != -1);
+      return (prec << 1) | !TYPE_UNSIGNED (type);
+    }
 }
 
 /* Helper routine that returns ADDR_EXPR of a VAR_DECL of a type
@@ -891,6 +898,130 @@  instrument_bool_enum_load (gimple_stmt_iterator *gsi)
   gsi_insert_before (&gsi2, g, GSI_SAME_STMT);
 }
 
+/* Instrument float point-to-integer conversion.  TYPE is an integer type of
+   destination, EXPR is floating-point expression.  */
+
+tree
+ubsan_instrument_float_cast (location_t loc, tree type, tree expr)
+{
+  tree expr_type = TREE_TYPE (expr);
+  tree t, tt, fn, min, max;
+  enum machine_mode mode = TYPE_MODE (expr_type);
+  int prec = TYPE_PRECISION (type);
+  bool uns_p = TYPE_UNSIGNED (type);
+
+  /* Float to integer conversion first truncates toward zero, so
+     even signed char c = 127.875f; is not problematic.
+     Therefore, we should complain only if EXPR is unordered or smaller
+     or equal than TYPE_MIN_VALUE - 1.0 or greater or equal than
+     TYPE_MAX_VALUE + 1.0.  */
+  if (REAL_MODE_FORMAT (mode)->b == 2)
+    {
+      /* For maximum, TYPE_MAX_VALUE might not be representable
+	 in EXPR_TYPE, e.g. if TYPE is 64-bit long long and
+	 EXPR_TYPE is IEEE single float, but TYPE_MAX_VALUE + 1.0 is
+	 either representable or infinity.  */
+      REAL_VALUE_TYPE maxval = dconst1;
+      SET_REAL_EXP (&maxval, REAL_EXP (&maxval) + prec - !uns_p);
+      real_convert (&maxval, mode, &maxval);
+      max = build_real (expr_type, maxval);
+
+      /* For unsigned, assume -1.0 is always representable.  */
+      if (uns_p)
+	min = build_minus_one_cst (expr_type);
+      else
+	{
+	  /* TYPE_MIN_VALUE is generally representable (or -inf),
+	     but TYPE_MIN_VALUE - 1.0 might not be.  */
+	  REAL_VALUE_TYPE minval = dconstm1, minval2;
+	  SET_REAL_EXP (&minval, REAL_EXP (&minval) + prec - 1);
+	  real_convert (&minval, mode, &minval);
+	  real_arithmetic (&minval2, MINUS_EXPR, &minval, &dconst1);
+	  real_convert (&minval2, mode, &minval2);
+	  if (real_compare (EQ_EXPR, &minval, &minval2)
+	      && !real_isinf (&minval))
+	    {
+	      /* If TYPE_MIN_VALUE - 1.0 is not representable and
+		 rounds to TYPE_MIN_VALUE, we need to subtract
+		 more.  As REAL_MODE_FORMAT (mode)->p is the number
+		 of base digits, we want to subtract a number that
+		 will be 1 << (REAL_MODE_FORMAT (mode)->p - 1)
+		 times smaller than minval.  */
+	      minval2 = dconst1;
+	      gcc_assert (prec > REAL_MODE_FORMAT (mode)->p);
+	      SET_REAL_EXP (&minval2,
+			    REAL_EXP (&minval2) + prec - 1
+			    - REAL_MODE_FORMAT (mode)->p + 1);
+	      real_arithmetic (&minval2, MINUS_EXPR, &minval, &minval2);
+	      real_convert (&minval2, mode, &minval2);
+	    }
+	  min = build_real (expr_type, minval2);
+	}
+    }
+  else if (REAL_MODE_FORMAT (mode)->b == 10)
+    {
+      /* For _Decimal128 up to 34 decimal digits, - sign,
+	 dot, e, exponent.  */
+      char buf[64];
+      mpfr_t m;
+      int p = REAL_MODE_FORMAT (mode)->p;
+      REAL_VALUE_TYPE maxval, minval;
+
+      /* Use mpfr_snprintf rounding to compute the smallest
+	 representable decimal number greater or equal than
+	 1 << (prec - !uns_p).  */
+      mpfr_init2 (m, prec + 2);
+      mpfr_set_ui_2exp (m, 1, prec - !uns_p, GMP_RNDN);
+      mpfr_snprintf (buf, sizeof buf, "%.*RUe", p - 1, m);
+      decimal_real_from_string (&maxval, buf);
+      max = build_real (expr_type, maxval);
+
+      /* For unsigned, assume -1.0 is always representable.  */
+      if (uns_p)
+	min = build_minus_one_cst (expr_type);
+      else
+	{
+	  /* Use mpfr_snprintf rounding to compute the largest
+	     representable decimal number less or equal than
+	     (-1 << (prec - 1)) - 1.  */
+	  mpfr_set_si_2exp (m, -1, prec - 1, GMP_RNDN);
+	  mpfr_sub_ui (m, m, 1, GMP_RNDN);
+	  mpfr_snprintf (buf, sizeof buf, "%.*RDe", p - 1, m);
+	  decimal_real_from_string (&minval, buf);
+	  min = build_real (expr_type, minval);
+	}
+      mpfr_clear (m);
+    }
+  else
+    return NULL_TREE;
+
+  if (flag_sanitize_undefined_trap_on_error)
+    fn = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
+  else
+    {
+      /* Create the __ubsan_handle_float_cast_overflow fn call.  */
+      tree data = ubsan_create_data ("__ubsan_float_cast_overflow_data", NULL,
+				     NULL,
+				     ubsan_type_descriptor (expr_type, false),
+				     ubsan_type_descriptor (type, false),
+				     NULL_TREE);
+      enum built_in_function bcode
+	= flag_sanitize_recover
+	  ? BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW
+	  : BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW_ABORT;
+      fn = builtin_decl_explicit (bcode);
+      fn = build_call_expr_loc (loc, fn, 2,
+				build_fold_addr_expr_loc (loc, data),
+				ubsan_encode_value (expr, false));
+    }
+
+  t = fold_build2 (UNLE_EXPR, boolean_type_node, expr, min);
+  tt = fold_build2 (UNGE_EXPR, boolean_type_node, expr, max);
+  return fold_build3 (COND_EXPR, void_type_node,
+		      fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt),
+		      fn, integer_zero_node);
+}
+
 namespace {
 
 const pass_data pass_data_ubsan =
diff --git gcc/ubsan.h gcc/ubsan.h
index 67cc6e9..b008419 100644
--- gcc/ubsan.h
+++ gcc/ubsan.h
@@ -44,6 +44,7 @@  extern tree ubsan_type_descriptor (tree, bool);
 extern tree ubsan_encode_value (tree, bool = false);
 extern bool is_ubsan_builtin_p (tree);
 extern tree ubsan_build_overflow_builtin (tree_code, location_t, tree, tree, tree);
+extern tree ubsan_instrument_float_cast (location_t, tree, tree);
 
 #endif  /* GCC_UBSAN_H  */