diff mbox

Fix lrint, llrint missing exceptions close to overflow threshold (bug 19094) [committed]

Message ID alpine.DEB.2.10.1510082218100.8465@digraph.polyomino.org.uk
State New
Headers show

Commit Message

Joseph Myers Oct. 8, 2015, 10:18 p.m. UTC
The dbl-64, ldbl-96 and ldbl-128 implementations of lrint and llrint
fail to produce "invalid" exceptions in cases where the rounded result
overflows the target type, but truncating the floating-point argument
to the next integer towards zero does not overflow it (so in
particular casts do not produce such exceptions).  (This issue cannot
arise for float, or for double with 64-bit target type, or for ldbl-96
with 64-bit target type and negative arguments, because of
insufficient precision in the floating-point type for arguments with
the relevant property to exist.  It also obviously cannot arise in
FE_TOWARDZERO mode.)

This patch fixes these problems by inserting checks for the special
cases that can occur in each implementation, and explicitly raising
FE_INVALID (and avoiding the cast if it might raise spurious
FE_INEXACT, while raising FE_INEXACT explicitly in the cases where it
is needed; unlike lround and llround, FE_INEXACT is required, not
optional, for these functions for a within-range inexact result).

The fixes are conditional on FE_INVALID or FE_INEXACT being defined.
If any future architecture supports one but not both of those
exceptions, the code will fail to compile and need fixing to handle
that case (this seemed better than conditioning on both macros being
defined, resulting in code that would compile but quietly miss
exceptions on such a system).

Tested for x86_64, x86 and mips64.  Tested the ldbl-96 changes (only
relevant for ia64, it appears) on x86_64 by removing the x86_64
versions of lrintl / llrintl.  Committed.

2015-10-08  Joseph Myers  <joseph@codesourcery.com>

	[BZ #19094]
	* sysdeps/ieee754/dbl-64/s_lrint.c: Include <fenv.h> and
	<limits.h>.
	(__lrint) [FE_INVALID || FE_INEXACT]: Force FE_INVALID exception
	when result overflows but exception would not result from cast.
	* sysdeps/ieee754/ldbl-128/s_llrintl.c: Include <fenv.h> and
	<limits.h>.
	(__llrintl) [FE_INVALID || FE_INEXACT]: Force FE_INVALID exception
	when result overflows but exception would not result from cast.
	* sysdeps/ieee754/ldbl-128/s_lrintl.c: Include <fenv.h> and
	<limits.h>.
	(__lrintl) [FE_INVALID || FE_INEXACT]: Force FE_INVALID exception
	when result overflows but exception would not result from cast.
	* sysdeps/ieee754/ldbl-96/s_llrintl.c: Include <fenv.h> and
	<limits.h>.
	(__llrintl) [FE_INVALID || FE_INEXACT]: Force FE_INVALID exception
	when result overflows but exception would not result from cast.
	* sysdeps/ieee754/ldbl-96/s_lrintl.c: Include <fenv.h> and
	<limits.h>.
	(__lrintl) [FE_INVALID || FE_INEXACT]: Force FE_INVALID exception
	when result overflows but exception would not result from cast.
	* math/libm-test.inc (lrint_test_data): Add more tests.
	(llrint_test_data): Likewise.

Comments

H.J. Lu Oct. 9, 2015, 5:19 p.m. UTC | #1
On Thu, Oct 8, 2015 at 3:18 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> The dbl-64, ldbl-96 and ldbl-128 implementations of lrint and llrint
> fail to produce "invalid" exceptions in cases where the rounded result
> overflows the target type, but truncating the floating-point argument
> to the next integer towards zero does not overflow it (so in
> particular casts do not produce such exceptions).  (This issue cannot
> arise for float, or for double with 64-bit target type, or for ldbl-96
> with 64-bit target type and negative arguments, because of
> insufficient precision in the floating-point type for arguments with
> the relevant property to exist.  It also obviously cannot arise in
> FE_TOWARDZERO mode.)
>
> This patch fixes these problems by inserting checks for the special
> cases that can occur in each implementation, and explicitly raising
> FE_INVALID (and avoiding the cast if it might raise spurious
> FE_INEXACT, while raising FE_INEXACT explicitly in the cases where it
> is needed; unlike lround and llround, FE_INEXACT is required, not
> optional, for these functions for a within-range inexact result).
>
> The fixes are conditional on FE_INVALID or FE_INEXACT being defined.
> If any future architecture supports one but not both of those
> exceptions, the code will fail to compile and need fixing to handle
> that case (this seemed better than conditioning on both macros being
> defined, resulting in code that would compile but quietly miss
> exceptions on such a system).
>
> Tested for x86_64, x86 and mips64.  Tested the ldbl-96 changes (only
> relevant for ia64, it appears) on x86_64 by removing the x86_64
> versions of lrintl / llrintl.  Committed.
>
> 2015-10-08  Joseph Myers  <joseph@codesourcery.com>
>
>         [BZ #19094]
>         * sysdeps/ieee754/dbl-64/s_lrint.c: Include <fenv.h> and
>         <limits.h>.
>         (__lrint) [FE_INVALID || FE_INEXACT]: Force FE_INVALID exception
>         when result overflows but exception would not result from cast.
>         * sysdeps/ieee754/ldbl-128/s_llrintl.c: Include <fenv.h> and
>         <limits.h>.
>         (__llrintl) [FE_INVALID || FE_INEXACT]: Force FE_INVALID exception
>         when result overflows but exception would not result from cast.
>         * sysdeps/ieee754/ldbl-128/s_lrintl.c: Include <fenv.h> and
>         <limits.h>.
>         (__lrintl) [FE_INVALID || FE_INEXACT]: Force FE_INVALID exception
>         when result overflows but exception would not result from cast.
>         * sysdeps/ieee754/ldbl-96/s_llrintl.c: Include <fenv.h> and
>         <limits.h>.
>         (__llrintl) [FE_INVALID || FE_INEXACT]: Force FE_INVALID exception
>         when result overflows but exception would not result from cast.
>         * sysdeps/ieee754/ldbl-96/s_lrintl.c: Include <fenv.h> and
>         <limits.h>.
>         (__lrintl) [FE_INVALID || FE_INEXACT]: Force FE_INVALID exception
>         when result overflows but exception would not result from cast.
>         * math/libm-test.inc (lrint_test_data): Add more tests.
>         (llrint_test_data): Likewise.
>

I got

testing double (without inline functions)
Failure: lrint (0x1p31): Exception "Invalid operation" not set
Failure: lrint (0x1p32): Exception "Invalid operation" not set
Failure: lrint (0x1p33): Exception "Invalid operation" not set
Failure: lrint (-0x1p32): Exception "Invalid operation" not set
Failure: lrint (-0x1p33): Exception "Invalid operation" not set
Failure: lrint (-0x1p63): Exception "Invalid operation" not set
Failure: lrint_downward (0x1p31): Exception "Invalid operation" not set
Failure: lrint_downward (0x1p32): Exception "Invalid operation" not set
Failure: lrint_downward (0x1p33): Exception "Invalid operation" not set
Failure: lrint_downward (-0x1p32): Exception "Invalid operation" not set
Failure: lrint_downward (-0x1p33): Exception "Invalid operation" not set
Failure: lrint_downward (-0x1p63): Exception "Invalid operation" not set
Failure: lrint_towardzero (0x1p31): Exception "Invalid operation" not set
Failure: lrint_towardzero (0x1p32): Exception "Invalid operation" not set
Failure: lrint_towardzero (0x1p33): Exception "Invalid operation" not set
Failure: lrint_towardzero (-0x1p32): Exception "Invalid operation" not set
Failure: lrint_towardzero (-0x1p33): Exception "Invalid operation" not set
Failure: lrint_towardzero (-0x1p63): Exception "Invalid operation" not set
Failure: lrint_upward (0x1p31): Exception "Invalid operation" not set
Failure: lrint_upward (0x1p32): Exception "Invalid operation" not set
Failure: lrint_upward (0x1p33): Exception "Invalid operation" not set
Failure: lrint_upward (-0x1p32): Exception "Invalid operation" not set
Failure: lrint_upward (-0x1p33): Exception "Invalid operation" not set
Failure: lrint_upward (-0x1p63): Exception "Invalid operation" not set

Test suite completed:
  81782 test cases plus 74758 tests for exception flags and
    74758 tests for errno executed.
  24 errors occurred.

on x32.    Do you know why?
Joseph Myers Oct. 9, 2015, 5:27 p.m. UTC | #2
On Fri, 9 Oct 2015, H.J. Lu wrote:

> testing double (without inline functions)
> Failure: lrint (0x1p31): Exception "Invalid operation" not set
[...]
> 
> on x32.    Do you know why?

The x86_64 versions of lrint / lrintf / lrintl are aliases for the long 
long versions.  This isn't correct for x32, where exceptions must respect 
overflow for 32-bit long.  I think you need to write separate versions of 
the long functions for x32 that convert to 32-bit long and raise the right 
exceptions for that conversion, while keeping the aliases in the non-x32 
case.
diff mbox

Patch

diff --git a/math/libm-test.inc b/math/libm-test.inc
index cb738ca..652735d 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -7808,6 +7808,155 @@  static const struct test_f_l_data lrint_test_data[] =
 #endif
     TEST_f_l (lrint, -0x1p64, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
     TEST_f_l (lrint, -0x1p65, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lrint, 0x7fffff80p0, 0x7fffff80LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#ifndef TEST_FLOAT
+    TEST_f_l (lrint, 0x7fffffffp0, 0x7fffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# if LONG_MAX > 0x7fffffff
+    TEST_f_l (lrint, 0x7fffffff.4p0, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, 0x7fffffff.7ffffcp0, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, 0x7fffffff.8p0, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, 0x7fffffff.cp0, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# else
+    TEST_f_l (lrint, 0x7fffffff.4p0, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lrint, 0x7fffffff.7ffffcp0, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lrint, 0x7fffffff.8p0, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lrint, 0x7fffffff.cp0, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+#endif
+#if LONG_MAX > 0x7fffffff
+# if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64
+    TEST_f_l (lrint, 0x7fffffff.7fffffff8p0L, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# endif
+# if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+    TEST_f_l (lrint, 0x7fffffff.7fffffffffffffffffep0L, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# endif
+# if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+    TEST_f_l (lrint, 0x7fffffff.7fffffffffffffffffffcp0L, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# endif
+#else
+# if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64
+    TEST_f_l (lrint, 0x7fffffff.7fffffff8p0L, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+# if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+    TEST_f_l (lrint, 0x7fffffff.7fffffffffffffffffep0L, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+# if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+    TEST_f_l (lrint, 0x7fffffff.7fffffffffffffffffffcp0L, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+#endif
+#ifndef TEST_FLOAT
+# if LONG_MAX > 0x7fffffff
+    TEST_f_l (lrint, -0x80000000.4p0, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, -0x80000000.7ffff8p0, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, -0x80000000.8p0, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, -0x80000000.cp0, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, -0x80000001p0, -0x80000001LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# else
+    TEST_f_l (lrint, -0x80000000.4p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, -0x80000000.7ffff8p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, -0x80000000.8p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, -0x80000000.cp0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, -0x80000001p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+#endif
+#if LONG_MAX > 0x7fffffff
+    TEST_f_l (lrint, -0x80000100p0, -0x80000100LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#else
+    TEST_f_l (lrint, -0x80000100p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+#if LONG_MAX > 0x7fffffff
+# if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64
+    TEST_f_l (lrint, -0x80000000.7fffffffp0L, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# endif
+# if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+    TEST_f_l (lrint, -0x80000000.7fffffffffffffffffcp0L, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# endif
+# if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+    TEST_f_l (lrint, -0x80000000.7fffffffffffffffffff8p0L, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# endif
+#else
+# if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64
+    TEST_f_l (lrint, -0x80000000.7fffffffp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# endif
+# if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+    TEST_f_l (lrint, -0x80000000.7fffffffffffffffffcp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# endif
+# if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+    TEST_f_l (lrint, -0x80000000.7fffffffffffffffffff8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# endif
+#endif
+#if LONG_MAX > 0x7fffffff
+    TEST_f_l (lrint, 0x7fffff8000000000p0, 0x7fffff8000000000LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#else
+    TEST_f_l (lrint, 0x7fffff8000000000p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+#ifndef TEST_FLOAT
+# if LONG_MAX > 0x7fffffff
+    TEST_f_l (lrint, 0x7ffffffffffffc00p0, 0x7ffffffffffffc00LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# else
+    TEST_f_l (lrint, 0x7ffffffffffffc00p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+#endif
+#ifdef TEST_LDOUBLE
+# if LONG_MAX > 0x7fffffff
+    TEST_f_l (lrint, 0x7fffffffffffffffp0L, 0x7fffffffffffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, 0x7fffffffffffffff.8p0L, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# else
+    TEST_f_l (lrint, 0x7fffffffffffffffp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lrint, 0x7fffffffffffffff.8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+# if LDBL_MANT_DIG > 64
+#  if LONG_MAX > 0x7fffffff
+    TEST_f_l (lrint, 0x7fffffffffffffff.4p0L, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lrint, 0x7fffffffffffffff.cp0L, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#  else
+    TEST_f_l (lrint, 0x7fffffffffffffff.4p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lrint, 0x7fffffffffffffff.cp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#  endif
+# endif
+# if LONG_MAX > 0x7fffffff
+#  if LDBL_MANT_DIG >= 106
+    TEST_f_l (lrint, 0x7fffffffffffffff.7fffffffffep0L, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#  endif
+#  if LDBL_MANT_DIG >= 113
+    TEST_f_l (lrint, 0x7fffffffffffffff.7fffffffffffcp0L, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#  endif
+# else
+#  if LDBL_MANT_DIG >= 106
+    TEST_f_l (lrint, 0x7fffffffffffffff.7fffffffffep0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#  endif
+#  if LDBL_MANT_DIG >= 113
+    TEST_f_l (lrint, 0x7fffffffffffffff.7fffffffffffcp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#  endif
+# endif
+#endif
+#ifdef TEST_LDOUBLE
+    TEST_f_l (lrint, -0x8000000000000001p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+# if LONG_MAX > 0x7fffffff
+    TEST_f_l (lrint, -0x8000000000000000.4p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, -0x8000000000000000.7fffffffffcp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, -0x8000000000000000.8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lrint, -0x8000000000000000.cp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# else
+    TEST_f_l (lrint, -0x8000000000000000.4p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lrint, -0x8000000000000000.7fffffffffcp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lrint, -0x8000000000000000.8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lrint, -0x8000000000000000.cp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+#endif
+    TEST_f_l (lrint, -0x8000010000000000p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#ifndef TEST_FLOAT
+    TEST_f_l (lrint, -0x8000000000000800p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+# if LONG_MAX > 0x7fffffff
+    TEST_f_l (lrint, -0x8000000000000000.7fffffffffff8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# else
+    TEST_f_l (lrint, -0x8000000000000000.7fffffffffff8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+#endif
     TEST_f_l (lrint, 0.0, 0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_l (lrint, minus_zero, 0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_l (lrint, min_value, 0, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 1, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
@@ -7975,6 +8124,74 @@  static const struct test_f_L_data llrint_test_data[] =
     TEST_f_L (llrint, -0x1p63, LLONG_MIN, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_L (llrint, -0x1p64, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
     TEST_f_L (llrint, -0x1p65, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_L (llrint, 0x7fffff80p0, 0x7fffff80LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#ifndef TEST_FLOAT
+    TEST_f_L (llrint, 0x7fffffffp0, 0x7fffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llrint, 0x7fffffff.4p0, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llrint, 0x7fffffff.7ffffcp0, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llrint, 0x7fffffff.8p0, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llrint, 0x7fffffff.cp0, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64
+    TEST_f_L (llrint, 0x7fffffff.7fffffff8p0L, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+    TEST_f_L (llrint, 0x7fffffff.7fffffffffffffffffep0L, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+    TEST_f_L (llrint, 0x7fffffff.7fffffffffffffffffffcp0L, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
+#ifndef TEST_FLOAT
+    TEST_f_L (llrint, -0x80000000.4p0, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llrint, -0x80000000.7ffff8p0, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llrint, -0x80000000.8p0, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llrint, -0x80000000.cp0, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llrint, -0x80000001p0, -0x80000001LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
+    TEST_f_L (llrint, -0x80000100p0, -0x80000100LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64
+    TEST_f_L (llrint, -0x80000000.7fffffffp0L, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+    TEST_f_L (llrint, -0x80000000.7fffffffffffffffffcp0L, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+    TEST_f_L (llrint, -0x80000000.7fffffffffffffffffff8p0L, -0x80000001LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, -0x80000000LL, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
+    TEST_f_L (llrint, 0x7fffff8000000000p0, 0x7fffff8000000000LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#ifndef TEST_FLOAT
+    TEST_f_L (llrint, 0x7ffffffffffffc00p0, 0x7ffffffffffffc00LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
+#ifdef TEST_LDOUBLE
+    TEST_f_L (llrint, 0x7fffffffffffffffp0L, 0x7fffffffffffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llrint, 0x7fffffffffffffff.8p0L, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# if LDBL_MANT_DIG > 64
+    TEST_f_L (llrint, 0x7fffffffffffffff.4p0L, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_L (llrint, 0x7fffffffffffffff.cp0L, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+# if LDBL_MANT_DIG >= 106
+    TEST_f_L (llrint, 0x7fffffffffffffff.7fffffffffep0L, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+# if LDBL_MANT_DIG >= 113
+    TEST_f_L (llrint, 0x7fffffffffffffff.7fffffffffffcp0L, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0x7fffffffffffffffLL, INEXACT_EXCEPTION|ERRNO_UNCHANGED, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+#endif
+#ifdef TEST_LDOUBLE
+    TEST_f_L (llrint, -0x8000000000000001p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+    TEST_f_L (llrint, -0x8000000000000000.4p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llrint, -0x8000000000000000.7fffffffffcp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llrint, -0x8000000000000000.8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llrint, -0x8000000000000000.cp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
+    TEST_f_L (llrint, -0x8000010000000000p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#ifndef TEST_FLOAT
+    TEST_f_L (llrint, -0x8000000000000800p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+    TEST_f_L (llrint, -0x8000000000000000.7fffffffffff8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED, LLONG_MIN, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
     TEST_f_L (llrint, 0.0, 0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_L (llrint, minus_zero, 0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_L (llrint, min_value, 0, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 0, INEXACT_EXCEPTION|ERRNO_UNCHANGED, 1, INEXACT_EXCEPTION|ERRNO_UNCHANGED),
diff --git a/sysdeps/ieee754/dbl-64/s_lrint.c b/sysdeps/ieee754/dbl-64/s_lrint.c
index 353d5f5..39f95ad 100644
--- a/sysdeps/ieee754/dbl-64/s_lrint.c
+++ b/sysdeps/ieee754/dbl-64/s_lrint.c
@@ -18,6 +18,8 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <fenv.h>
+#include <limits.h>
 #include <math.h>
 
 #include <math_private.h>
@@ -62,8 +64,22 @@  __lrint (double x)
 	result = ((long int) i0 << (j0 - 20)) | (i1 << (j0 - 52));
       else
 	{
-	  w = math_narrow_eval (two52[sx] + x);
-	  t = w - two52[sx];
+#if defined FE_INVALID || defined FE_INEXACT
+	  /* X < LONG_MAX + 1 implied by J0 < 31.  */
+	  if (sizeof (long int) == 4
+	      && x > (double) LONG_MAX)
+	    {
+	      /* In the event of overflow we must raise the "invalid"
+		 exception, but not "inexact".  */
+	      t = __nearbyint (x);
+	      feraiseexcept (t == LONG_MAX ? FE_INEXACT : FE_INVALID);
+	    }
+	  else
+#endif
+	    {
+	      w = math_narrow_eval (two52[sx] + x);
+	      t = w - two52[sx];
+	    }
 	  EXTRACT_WORDS (i0, i1, t);
 	  j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
 	  i0 &= 0xfffff;
@@ -77,8 +93,21 @@  __lrint (double x)
     }
   else
     {
-      /* The number is too large.  It is left implementation defined
-	 what happens.  */
+      /* The number is too large.  Unless it rounds to LONG_MIN,
+	 FE_INVALID must be raised and the return value is
+	 unspecified.  */
+#if defined FE_INVALID || defined FE_INEXACT
+      if (sizeof (long int) == 4
+	  && x < (double) LONG_MIN
+	  && x > (double) LONG_MIN - 1.0)
+	{
+	  /* If truncation produces LONG_MIN, the cast will not raise
+	     the exception, but may raise "inexact".  */
+	  t = __nearbyint (x);
+	  feraiseexcept (t == LONG_MIN ? FE_INEXACT : FE_INVALID);
+	  return LONG_MIN;
+	}
+#endif
       return (long int) x;
     }
 
diff --git a/sysdeps/ieee754/ldbl-128/s_llrintl.c b/sysdeps/ieee754/ldbl-128/s_llrintl.c
index 77eb2d6..b9e2178 100644
--- a/sysdeps/ieee754/ldbl-128/s_llrintl.c
+++ b/sysdeps/ieee754/ldbl-128/s_llrintl.c
@@ -19,6 +19,8 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <fenv.h>
+#include <limits.h>
 #include <math.h>
 
 #include <math_private.h>
@@ -47,8 +49,21 @@  __llrintl (long double x)
 
   if (j0 < (int32_t) (8 * sizeof (long long int)) - 1)
     {
-      w = two112[sx] + x;
-      t = w - two112[sx];
+#if defined FE_INVALID || defined FE_INEXACT
+      /* X < LLONG_MAX + 1 implied by J0 < 63.  */
+      if (x > (long double) LLONG_MAX)
+	{
+	  /* In the event of overflow we must raise the "invalid"
+	     exception, but not "inexact".  */
+	  t = __nearbyintl (x);
+	  feraiseexcept (t == LLONG_MAX ? FE_INEXACT : FE_INVALID);
+	}
+      else
+#endif
+	{
+	  w = two112[sx] + x;
+	  t = w - two112[sx];
+	}
       GET_LDOUBLE_WORDS64 (i0, i1, t);
       j0 = ((i0 >> 48) & 0x7fff) - 0x3fff;
       i0 &= 0x0000ffffffffffffLL;
@@ -63,8 +78,20 @@  __llrintl (long double x)
     }
   else
     {
-      /* The number is too large.  It is left implementation defined
-	 what happens.  */
+      /* The number is too large.  Unless it rounds to LLONG_MIN,
+	 FE_INVALID must be raised and the return value is
+	 unspecified.  */
+#if defined FE_INVALID || defined FE_INEXACT
+      if (x < (long double) LLONG_MIN
+	  && x > (long double) LLONG_MIN - 1.0L)
+	{
+	  /* If truncation produces LLONG_MIN, the cast will not raise
+	     the exception, but may raise "inexact".  */
+	  t = __nearbyintl (x);
+	  feraiseexcept (t == LLONG_MIN ? FE_INEXACT : FE_INVALID);
+	  return LLONG_MIN;
+	}
+#endif
       return (long long int) x;
     }
 
diff --git a/sysdeps/ieee754/ldbl-128/s_lrintl.c b/sysdeps/ieee754/ldbl-128/s_lrintl.c
index d0b0aeb..cb5a75b 100644
--- a/sysdeps/ieee754/ldbl-128/s_lrintl.c
+++ b/sysdeps/ieee754/ldbl-128/s_lrintl.c
@@ -19,6 +19,8 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <fenv.h>
+#include <limits.h>
 #include <math.h>
 
 #include <math_private.h>
@@ -49,8 +51,22 @@  __lrintl (long double x)
     {
       if (j0 < 48)
 	{
-	  w = two112[sx] + x;
-	  t = w - two112[sx];
+#if defined FE_INVALID || defined FE_INEXACT
+	  /* X < LONG_MAX + 1 implied by J0 < 31.  */
+	  if (sizeof (long int) == 4
+	      && x > (long double) LONG_MAX)
+	    {
+	      /* In the event of overflow we must raise the "invalid"
+		 exception, but not "inexact".  */
+	      t = __nearbyintl (x);
+	      feraiseexcept (t == LONG_MAX ? FE_INEXACT : FE_INVALID);
+	    }
+	  else
+#endif
+	    {
+	      w = two112[sx] + x;
+	      t = w - two112[sx];
+	    }
 	  GET_LDOUBLE_WORDS64 (i0, i1, t);
 	  j0 = ((i0 >> 48) & 0x7fff) - 0x3fff;
 	  i0 &= 0x0000ffffffffffffLL;
@@ -62,8 +78,22 @@  __lrintl (long double x)
 	result = ((long int) i0 << (j0 - 48)) | (i1 << (j0 - 112));
       else
 	{
-	  w = two112[sx] + x;
-	  t = w - two112[sx];
+#if defined FE_INVALID || defined FE_INEXACT
+	  /* X < LONG_MAX + 1 implied by J0 < 63.  */
+	  if (sizeof (long int) == 8
+	      && x > (long double) LONG_MAX)
+	    {
+	      /* In the event of overflow we must raise the "invalid"
+		 exception, but not "inexact".  */
+	      t = __nearbyintl (x);
+	      feraiseexcept (t == LONG_MAX ? FE_INEXACT : FE_INVALID);
+	    }
+	  else
+#endif
+	    {
+	      w = two112[sx] + x;
+	      t = w - two112[sx];
+	    }
 	  GET_LDOUBLE_WORDS64 (i0, i1, t);
 	  j0 = ((i0 >> 48) & 0x7fff) - 0x3fff;
 	  i0 &= 0x0000ffffffffffffLL;
@@ -77,8 +107,20 @@  __lrintl (long double x)
     }
   else
     {
-      /* The number is too large.  It is left implementation defined
-	 what happens.  */
+      /* The number is too large.  Unless it rounds to LONG_MIN,
+	 FE_INVALID must be raised and the return value is
+	 unspecified.  */
+#if defined FE_INVALID || defined FE_INEXACT
+      if (x < (long double) LONG_MIN
+	  && x > (long double) LONG_MIN - 1.0L)
+	{
+	  /* If truncation produces LONG_MIN, the cast will not raise
+	     the exception, but may raise "inexact".  */
+	  t = __nearbyintl (x);
+	  feraiseexcept (t == LONG_MIN ? FE_INEXACT : FE_INVALID);
+	  return LONG_MIN;
+	}
+#endif
       return (long int) x;
     }
 
diff --git a/sysdeps/ieee754/ldbl-96/s_llrintl.c b/sysdeps/ieee754/ldbl-96/s_llrintl.c
index c73741e..e3faa21 100644
--- a/sysdeps/ieee754/ldbl-96/s_llrintl.c
+++ b/sysdeps/ieee754/ldbl-96/s_llrintl.c
@@ -18,6 +18,8 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <fenv.h>
+#include <limits.h>
 #include <math.h>
 
 #include <math_private.h>
@@ -50,8 +52,21 @@  __llrintl (long double x)
 	result = (((long long int) i0 << 32) | i1) << (j0 - 63);
       else
 	{
-	  w = two63[sx] + x;
-	  t = w - two63[sx];
+#if defined FE_INVALID || defined FE_INEXACT
+	  /* X < LLONG_MAX + 1 implied by J0 < 63.  */
+	  if (x > (long double) LLONG_MAX)
+	    {
+	      /* In the event of overflow we must raise the "invalid"
+		 exception, but not "inexact".  */
+	      t = __nearbyintl (x);
+	      feraiseexcept (t == LLONG_MAX ? FE_INEXACT : FE_INVALID);
+	    }
+	  else
+#endif
+	    {
+	      w = two63[sx] + x;
+	      t = w - two63[sx];
+	    }
 	  GET_LDOUBLE_WORDS (se, i0, i1, t);
 	  j0 = (se & 0x7fff) - 0x3fff;
 
diff --git a/sysdeps/ieee754/ldbl-96/s_lrintl.c b/sysdeps/ieee754/ldbl-96/s_lrintl.c
index 598423b..4dd1993 100644
--- a/sysdeps/ieee754/ldbl-96/s_lrintl.c
+++ b/sysdeps/ieee754/ldbl-96/s_lrintl.c
@@ -18,6 +18,8 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <fenv.h>
+#include <limits.h>
 #include <math.h>
 
 #include <math_private.h>
@@ -46,8 +48,22 @@  __lrintl (long double x)
 
   if (j0 < 31)
     {
-      w = two63[sx] + x;
-      t = w - two63[sx];
+#if defined FE_INVALID || defined FE_INEXACT
+      /* X < LONG_MAX + 1 implied by J0 < 31.  */
+      if (sizeof (long int) == 4
+	  && x > (long double) LONG_MAX)
+	{
+	  /* In the event of overflow we must raise the "invalid"
+	     exception, but not "inexact".  */
+	  t = __nearbyintl (x);
+	  feraiseexcept (t == LONG_MAX ? FE_INEXACT : FE_INVALID);
+	}
+      else
+#endif
+	{
+	  w = two63[sx] + x;
+	  t = w - two63[sx];
+	}
       GET_LDOUBLE_WORDS (se, i0, i1, t);
       j0 = (se & 0x7fff) - 0x3fff;
 
@@ -59,8 +75,22 @@  __lrintl (long double x)
 	result = ((long int) i0 << (j0 - 31)) | (i1 << (j0 - 63));
       else
 	{
-	  w = two63[sx] + x;
-	  t = w - two63[sx];
+#if defined FE_INVALID || defined FE_INEXACT
+	  /* X < LONG_MAX + 1 implied by J0 < 63.  */
+	  if (sizeof (long int) == 8
+	      && x > (long double) LONG_MAX)
+	    {
+	      /* In the event of overflow we must raise the "invalid"
+		 exception, but not "inexact".  */
+	      t = __nearbyintl (x);
+	      feraiseexcept (t == LONG_MAX ? FE_INEXACT : FE_INVALID);
+	    }
+	  else
+#endif
+	    {
+	      w = two63[sx] + x;
+	      t = w - two63[sx];
+	    }
 	  GET_LDOUBLE_WORDS (se, i0, i1, t);
 	  j0 = (se & 0x7fff) - 0x3fff;
 
@@ -72,8 +102,21 @@  __lrintl (long double x)
     }
   else
     {
-      /* The number is too large.  It is left implementation defined
-	 what happens.  */
+      /* The number is too large.  Unless it rounds to LONG_MIN,
+	 FE_INVALID must be raised and the return value is
+	 unspecified.  */
+#if defined FE_INVALID || defined FE_INEXACT
+      if (sizeof (long int) == 4
+	  && x < (long double) LONG_MIN
+	  && x > (long double) LONG_MIN - 1.0L)
+	{
+	  /* If truncation produces LONG_MIN, the cast will not raise
+	     the exception, but may raise "inexact".  */
+	  t = __nearbyintl (x);
+	  feraiseexcept (t == LONG_MIN ? FE_INEXACT : FE_INVALID);
+	  return LONG_MIN;
+	}
+#endif
       return (long int) x;
     }