diff --git a/gcc/testsuite/gcc.dg/torture/bitint-63.c b/gcc/testsuite/gcc.dg/torture/bitint-63.c new file mode 100644 index 00000000000..97acba0fa1e --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/bitint-63.c @@ -0,0 +1,30 @@ +/* PR libgcc/114327 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23" } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */ + +#if __BITINT_MAXWIDTH__ >= 256 +_BitInt(256) +foo (_BitInt(256) b, _BitInt(256) c) +{ + return b % c; +} + +_BitInt(256) +bar (_BitInt(256) b, _BitInt(256) c) +{ + return b / c; +} +#endif + +int +main () +{ +#if __BITINT_MAXWIDTH__ >= 256 + if (foo (-0x9e9b9fe60wb, 1wb)) + __builtin_abort (); + if (bar (1wb, -0x9e9b9fe60wb)) + __builtin_abort (); +#endif +} diff --git a/libgcc/libgcc2.c b/libgcc/libgcc2.c index ef46153731f..dc856740a69 100644 --- a/libgcc/libgcc2.c +++ b/libgcc/libgcc2.c @@ -1642,19 +1642,22 @@ __mulbitint3 (UBILtype *ret, SItype retprec, #ifdef L_divmodbitint4 /* D = -S. */ -static void +static UWtype bitint_negate (UBILtype *d, const UBILtype *s, SItype n) { UWtype c = 1; + UWtype r = 0; do { UWtype sv = *s, lo; + r |= sv; s += BITINT_INC; c = __builtin_add_overflow (~sv, c, &lo); *d = lo; d += BITINT_INC; } while (--n); + return r; } /* D -= S * L. */ @@ -1977,10 +1980,10 @@ __divmodbitint4 (UBILtype *q, SItype qprec, n = qn; else n = un - vn + 1; - bitint_negate (q + BITINT_END (qn - 1, 0), - q2 + BITINT_END (un - vn, 0), n); + SItype c = bitint_negate (q + BITINT_END (qn - 1, 0), + q2 + BITINT_END (un - vn, 0), n) ? -1 : 0; if (qn > n) - __builtin_memset (q + BITINT_END (0, n), -1, + __builtin_memset (q + BITINT_END (0, n), c, (qn - n) * sizeof (UWtype)); } else @@ -1999,11 +2002,11 @@ __divmodbitint4 (UBILtype *q, SItype qprec, if (uprec < 0) { /* Negative remainder. */ - bitint_negate (r + BITINT_END (rn - 1, 0), - r + BITINT_END (rn - 1, 0), - rn > vn ? vn : rn); + SItype c = bitint_negate (r + BITINT_END (rn - 1, 0), + r + BITINT_END (rn - 1, 0), + rn > vn ? vn : rn) ? -1 : 0; if (rn > vn) - __builtin_memset (r + BITINT_END (0, vn), -1, + __builtin_memset (r + BITINT_END (0, vn), c, (rn - vn) * sizeof (UWtype)); } else