Thanks for all your help.  This is updated patch which:

* uses mix/min handling that Jakub kindly wrote,
* limited a test to ilp32 || lp64 + used sse2_runtime (but it's likely
  I screwed it up as usually),
* adds a testcase for (unsigned) __int128,
* adds testcases for C and C++ bit-fields,
* makes -fsanitize=float-cast-overflow be not enabled by default,
* is tested with -m32/-m64 on x86_64/ppc64,
* is missing tests for long doubles/-mlong-double-128,
* doesn't instrument _Decimal to integer conversions yet.

Comments?

2014-05-20  Marek Polacek  <pola...@redhat.com>
            Jakub Jelinek  <ja...@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.
        * g++.dg/ubsan/float-cast-overflow-bf.C: New test.
        * gcc.dg/ubsan/float-cast-overflow-bf.c: New test.

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..fadd8a8 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,229 @@
+/* { 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>
+
+int
+main (void)
+{
+  const double inf = __builtin_inf ();
+  const double nan = __builtin_nan ("");
+  volatile double d;
+
+#define CHECK_BOUNDARY(VAR, VAL)       \
+  (VAR) = (VAL) - 5.0;                 \
+  (VAR) = (VAL) - 1.5;                 \
+  (VAR) = (VAL) - 1.0;                 \
+  (VAR) = (VAL) - 0.9999999;           \
+  (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.9999999;           \
+  (VAR) = (VAL) + 1.0;                 \
+  (VAR) = (VAL) + 1.5;                 \
+  (VAR) = (VAL) + 5.0;
+
+#define CHECK_NONNUMBERS(VAR)          \
+  (VAR) = nan;                         \
+  (VAR) = -nan;                        \
+  (VAR) = inf;                         \
+  (VAR) = -inf;
+
+  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 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 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..af593ba 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,98 @@
+/* { dg-do run } */
+/* { dg-require-effective-target int128 } */
+/* { dg-options "-fsanitize=float-cast-overflow" } */
+
+#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)
+
+int
+main (void)
+{
+  const double inf = __builtin_inf ();
+  const double nan = __builtin_nan ("");
+  volatile double d;
+
+#define CHECK_BOUNDARY(VAR, VAL)       \
+  (VAR) = (VAL) - 5.0;                 \
+  (VAR) = (VAL) - 1.5;                 \
+  (VAR) = (VAL) - 1.0;                 \
+  (VAR) = (VAL) - 0.9999999;           \
+  (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.9999999;           \
+  (VAR) = (VAL) + 1.0;                 \
+  (VAR) = (VAL) + 1.5;                 \
+  (VAR) = (VAL) + 5.0;
+
+#define CHECK_NONNUMBERS(VAR)          \
+  (VAR) = nan;                         \
+  (VAR) = -nan;                                \
+  (VAR) = inf;                         \
+  (VAR) = -inf;
+
+  __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/g++.dg/ubsan/float-cast-overflow-bf.C 
gcc/testsuite/g++.dg/ubsan/float-cast-overflow-bf.C
index e69de29..20eb13c 100644
--- gcc/testsuite/g++.dg/ubsan/float-cast-overflow-bf.C
+++ gcc/testsuite/g++.dg/ubsan/float-cast-overflow-bf.C
@@ -0,0 +1,60 @@
+// { 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.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.  (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..62aeefc 100644
--- gcc/testsuite/gcc.dg/ubsan/float-cast-overflow-bf.c
+++ gcc/testsuite/gcc.dg/ubsan/float-cast-overflow-bf.c
@@ -0,0 +1,76 @@
+/* { 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.9999999;            \
+  (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.9999999;            \
+  (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 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 -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  */
 
        Marek

Reply via email to