From 0413057e561e91f4228d886b40a2045e0656294d Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 21 Apr 2026 11:53:52 +0200 Subject: [PATCH] bitintlower: Padding bit fixes, part 4 [PR123635] As the following testcase shows, not clearing the padding bits after signed MULT_EXPR (or signed division) is reasonable when overflow actually is undefined behavior because then anything can happen. But when it is not undefined behavior due to -fwrapv, we need to clear the padding bits on targets which chose that behavior. It isn't only signed MULT_EXPR, but also division because smallest negative / -1 overflows and in that case the padding bits aren't correct for bitint_extended targets either. 2026-04-21 Jakub Jelinek PR middle-end/123635 * gimple-lower-bitint.cc (bitint_large_huge::lower_muldiv_stmt): Extend the padding bits not just for unsigned MULT_EXPR but for any TYPE_OVERFLOW_WRAPS MULT_EXPR and signed TYPE_OVERFLOW_WRAPS division. * gcc.dg/torture/bitint-90.c: New test. Reviewed-by: Richard Biener --- gcc/gimple-lower-bitint.cc | 58 ++++++++++++++++++------ gcc/testsuite/gcc.dg/torture/bitint-90.c | 57 +++++++++++++++++++++++ 2 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/torture/bitint-90.c diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc index 24645aac243..fc8e1c25609 100644 --- a/gcc/gimple-lower-bitint.cc +++ b/gcc/gimple-lower-bitint.cc @@ -4085,7 +4085,8 @@ bitint_large_huge::lower_muldiv_stmt (tree obj, gimple *stmt) gcc_assert (TREE_CODE (type) == BITINT_TYPE && bitint_precision_kind (type) >= bitint_prec_large); int prec = TYPE_PRECISION (type), prec1, prec2; - bool zero_ms_limb = false; + bool ext_ms_limb = false; + bool do_ext = false; rhs1 = handle_operand_addr (rhs1, stmt, NULL, &prec1); rhs2 = handle_operand_addr (rhs2, stmt, NULL, &prec2); if (obj == NULL_TREE) @@ -4101,15 +4102,26 @@ bitint_large_huge::lower_muldiv_stmt (tree obj, gimple *stmt) lhs = force_gimple_operand_gsi (&m_gsi, lhs, true, NULL_TREE, true, GSI_SAME_STMT); } + if (bitint_extended && TYPE_OVERFLOW_WRAPS (type)) + { + if (rhs_code == MULT_EXPR) + do_ext = true; + /* For signed division with -fwrapv, minimum negative / -1 needs + is minimum negative and the padding bits above it should be all + set. */ + else if (!TYPE_UNSIGNED (type) + && (rhs_code == TRUNC_DIV_EXPR || rhs_code == EXACT_DIV_EXPR)) + do_ext = true; + } if (bitint_extended == bitint_ext_full && abi_limb_prec > limb_prec && (CEIL (prec, abi_limb_prec) * abi_limb_prec > CEIL (prec, limb_prec) * limb_prec)) { /* unsigned multiplication needs to wrap around, so we can't - increase prec. */ - if (rhs_code == MULT_EXPR && TYPE_UNSIGNED (type)) - zero_ms_limb = true; + increase prec. Similarly for -fwrapv. */ + if (do_ext) + ext_ms_limb = true; else prec = CEIL (prec, abi_limb_prec) * abi_limb_prec; } @@ -4166,10 +4178,8 @@ bitint_large_huge::lower_muldiv_stmt (tree obj, gimple *stmt) add_eh_edge (e2->src, e1); } } - if (bitint_extended - && rhs_code == MULT_EXPR - && TYPE_UNSIGNED (type) - && (prec % limb_prec) != 0) + if (do_ext + && ((prec % limb_prec) != 0 || (ext_ms_limb && !TYPE_UNSIGNED (type)))) { /* Unsigned multiplication wraps, but libgcc function will return the bits beyond prec within the top limb as another limb of the full @@ -4180,13 +4190,33 @@ bitint_large_huge::lower_muldiv_stmt (tree obj, gimple *stmt) tree v = make_ssa_name (m_limb_type); g = gimple_build_assign (v, l); insert_before (g); - v = add_cast (ctype, v); - l = limb_access (type, obj, idx, true); - v = add_cast (m_limb_type, v); - g = gimple_build_assign (l, v); - insert_before (g); + tree v2 = v; + if ((prec % limb_prec) != 0) + { + v = add_cast (ctype, v); + l = limb_access (type, obj, idx, true); + v = add_cast (m_limb_type, v); + v2 = v; + g = gimple_build_assign (l, v); + insert_before (g); + } + if (ext_ms_limb && !TYPE_UNSIGNED (type)) + { + v2 = add_cast (signed_type_for (m_limb_type), v2); + tree lpm1 = build_int_cst (unsigned_type_node, limb_prec - 1); + v = make_ssa_name (TREE_TYPE (v2)); + g = gimple_build_assign (v, RSHIFT_EXPR, v2, lpm1); + insert_before (g); + unsigned int i + = CEIL (prec, abi_limb_prec) * abi_limb_prec / limb_prec; + v = add_cast (m_limb_type, v); + g = gimple_build_assign (limb_access (type, obj, size_int (i - 1), + true), v); + insert_before (g); + ext_ms_limb = false; + } } - if (zero_ms_limb) + if (ext_ms_limb) { unsigned int i = CEIL (prec, abi_limb_prec) * abi_limb_prec / limb_prec; g = gimple_build_assign (limb_access (type, obj, size_int (i - 1), true), diff --git a/gcc/testsuite/gcc.dg/torture/bitint-90.c b/gcc/testsuite/gcc.dg/torture/bitint-90.c new file mode 100644 index 00000000000..9218b4ac884 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/bitint-90.c @@ -0,0 +1,57 @@ +/* PR middle-end/123635 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23 -pedantic-errors -fwrapv" } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */ + +#if __BITINT_MAXWIDTH__ >= 513 +_BitInt(513) a, b, c, d, e, f; +#endif + +#include "../bitintext.h" + +#if __BITINT_MAXWIDTH__ >= 513 +[[gnu::noipa]] void +f1 (_BitInt(513) q, _BitInt(513) r, _BitInt(513) s, _BitInt(513) t) +{ + a = q * r; + BEXTC (a); + b = s * t; + BEXTC (b); + c = q / r; + BEXTC (c); + d = s / t; + BEXTC (d); + e = q % r; + BEXTC (e); + f = s % t; + BEXTC (f); +} +#endif + +int +main () +{ +#if __BITINT_MAXWIDTH__ >= 513 + __builtin_memset (&a, 0x55, sizeof (a)); + __builtin_memset (&b, 0xaa, sizeof (b)); + __builtin_memset (&c, 0x55, sizeof (c)); + __builtin_memset (&d, 0xaa, sizeof (d)); + __builtin_memset (&e, 0x55, sizeof (e)); + __builtin_memset (&f, 0xaa, sizeof (f)); + f1 (-2569442167708526883032321549154973033917914038435073849581606377835896531300464410672941576709766056731856560073179286923714310748484353548564505224275735wb, + 2168258207301112123000422415459500116718298091852207369853333917415269374034197937707930701823104675221367858731870896332002496458560727651061447629500290wb, + -13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095wb - 1, + -1wb); + __builtin_memset (&a, 0x55, sizeof (a)); + __builtin_memset (&b, 0xaa, sizeof (b)); + __builtin_memset (&c, 0x55, sizeof (c)); + __builtin_memset (&d, 0xaa, sizeof (d)); + __builtin_memset (&e, 0x55, sizeof (e)); + __builtin_memset (&f, 0xaa, sizeof (f)); + f1 (11182751058163266900062523691585082292935101550776465927580156147436400116827277563246395892657460272253702154027346376026845302222986890807879025959971622wb, + 8164167338045748506210025483965624248110931799582481638963258497469488589147418794642910866480254020122096903001279978332046522756597851796198650349835611wb, + -10069248634646183494877194696541551363329286638973022393951487924262590826071711445633243661699089159257055025645295791432791410100972241125609033584314602wb, + -8066635266964063729231989957397398910332013431298049172762795336443651271867788598667551930170370590334905534762032999936946715583168838873523754981312676wb); +#endif +} -- 2.47.3