This patch fixes a miscompilation issue involving large constant _BitInt
values on some targets. A test case reproducing the issue is included in
the patch.
During bitint lowering, when a large constant _BitInt appears as a PHI
argument, a constant object is emitted into the .rodata section. Since
the size of the constant object in .rodata may be smaller than the
precision of the _BitInt type, a GIMPLE statement is built to zero- or
sign-extend the constant at runtime. In the current GCC implementation,
the extension offset is computed from the size of the constant object,
using `TYPE_SIZE_UNIT (TREE_TYPE (c))`.
On some targets, such as AArch64, the ABI limb precision (128 bits) is
higher than the limb precision (64 bits). Because constant objects are
emitted with a size that is multiple of the ABI limb precision, the most
significant 64 bits may consist of padding only. As a result, the size
of the constant object in .rodata doesn't accurately reflect the correct
extension offset. This can cause the zero- or sign-extension operation
to perform out-of-bounds stores, corrupting adjacent memory.
This patch computes the constant extension offsets from min_prec, using
`CEIL (min_prec, limb_prec) * limb_prec / BITS_PER_UNIT`, which reflects
the number of bytes of actual data represented by the constant.
This patch is bootstrapped and regression-tested on x86_64-linux-gnu,
arm-linux-gnueabihf and aarch64-linux-gnu.
gcc/ChangeLog:
PR middle-end/122689
* gimple-lower-bitint.cc (gimple_lower_bitint): Compute the
constant extension offset from min_prec.
gcc/testsuite/ChangeLog:
PR middle-end/122689
* gcc.dg/bitint-127.c: New test.
---
gcc/gimple-lower-bitint.cc | 25 +++++++++++++++++++++----
gcc/testsuite/gcc.dg/bitint-127.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/bitint-127.c
diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc
index 9d027c6a6a1..cbc5c3868e7 100644
--- a/gcc/gimple-lower-bitint.cc
+++ b/gcc/gimple-lower-bitint.cc
@@ -7816,8 +7816,18 @@ gimple_lower_bitint (void)
tree ptype = build_pointer_type (TREE_TYPE (v1));
tree off;
if (c && !bitint_big_endian)
- off = fold_convert (ptype,
- TYPE_SIZE_UNIT (TREE_TYPE (c)));
+ {
+ /* For targets with ABI limb precision higher than
+ limb precision, the type size of c may include ABI
+ padding bits and thus does not accurately describe
+ the zero-extension offset. So we need to compute
+ the offset from min_prec instead. */
+ unsigned HOST_WIDE_INT off_bytes
+ = CEIL (min_prec, limb_prec) * limb_prec
+ / BITS_PER_UNIT;
+ off = fold_convert (ptype,
+ build_int_cst (ptype, off_bytes));
+ }
else
off = build_zero_cst (ptype);
tree vd = build2 (MEM_REF, vtype,
@@ -7827,19 +7837,26 @@ gimple_lower_bitint (void)
else
{
tree vd = v1;
+ unsigned HOST_WIDE_INT off_bytes = 0;
if (c && !bitint_big_endian)
{
tree ptype = build_pointer_type (TREE_TYPE (v1));
+ /* Likewise, compute the sign-extension offset from
+ limb_prec rather than the type size. */
+ off_bytes = CEIL (min_prec, limb_prec) * limb_prec
+ / BITS_PER_UNIT;
tree off
= fold_convert (ptype,
- TYPE_SIZE_UNIT (TREE_TYPE (c)));
+ build_int_cst (ptype, off_bytes));
vd = build2 (MEM_REF, large_huge.m_limb_type,
build_fold_addr_expr (v1), off);
}
vd = build_fold_addr_expr (vd);
unsigned HOST_WIDE_INT nbytes
= tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (v1)));
- if (c)
+ if (c && !bitint_big_endian)
+ nbytes -= off_bytes;
+ else if (c)
nbytes
-= tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (c)));
tree fn = builtin_decl_implicit (BUILT_IN_MEMSET);
diff --git a/gcc/testsuite/gcc.dg/bitint-127.c
b/gcc/testsuite/gcc.dg/bitint-127.c
new file mode 100644
index 00000000000..a4e55de8832
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/bitint-127.c
@@ -0,0 +1,30 @@
+/* PR middle-end/122689 */
+/* { dg-do run { target { bitint } } } */
+/* { dg-options "-O1 -std=c23" } */
+
+#define MAX2(x, y) ({ \
+ __auto_type __x = x; \
+ __auto_type __y = y; \
+ __x >= __y ? __x : __y; \
+})
+
+#if __BITINT_MAXWIDTH__ >= 12419
+const _BitInt(12419) n =
0xfe65f7aff85d0095103ee4d1c3b9ca50eed67abd838cdc5b53c776c8dd19b0be6eeb21aa421395fc16cf018858c9c2a03b6a013546f938e5af4c286c0456a2f5e09ad52921a4f98ce6cfbdc1beee7b860507f9fbed6640a9ce12aab6ca7e54afa6113fefe2e91a2822e9f32e04c038bb2993f25afd9489117ba43f6d1389a527c0823fd096848c9ae857fac18d08ec59b8dc73df77213ec9d0b0fba9cb38213ac625a864ffe0d4c994be6692af55bdef84699596becccc0b48d6b306bed100e78defd85477a5d7eb57af5b84e70de61141f0e725b23bd26ee239fa91a8816a3b37480f8782564bb91dfc23277303553d302a0b67dbc914fab7f54ca91548bfe66eb9daa9e524509d96e94c502b7df14acf44ef09e9c4f50ad436a504f33e51210f5c4693fdbeb3a486ce7ec50ce18939936ca91e05afc11145461832f007622d19959c4dd5f508d8d60dfc9c79b7b504e5becbc0e09cef83b9a28aadb50bd3b3d071a688455831a697d7ebaa9f64fc106e2f4eb9f8edad3b5937e157d6a3d11f6c3f8a83cc2b737b8bbde90960eec3c1d629a2af864b25c9db8edee90d99e42b9948b247cd04052465da8a647ff3a4cfaa9c5cca2b4ead7e60c6b31cfcd6a5f62fe14d3ea6a914adbd7015ea3240faf3f453e5e135067bf71d4fc625a4318afeb0ba625a42e0294ffadbf356f149775ea67b9652d45cba63210becd0b8bca390c68c2be31842354eeff63e1b49b989d4de4ee11a12c812077e0062229749fd2fb0b129a8fe319a049d45baadd7e72dabe4a5276440468e78dca8ec8a129f6ce2da1a212fcc6610f1dd9eab2258492794fa6209a4a6e889e7a907f951eafe983bdda8dedf1d56af16909ce4281904c3035a8b2d3f4f3b2395f6f153da639a0265154f7fc51a3b4bada7aa6255a40544288348c4049e8d8507eada1ea5526aadfe23385bd72b1e4c0214ee962132c692ee13868e1ea4e5c53a5ff428ecda98e82c60fa01e8ced36edaee0740e19490f0c2c9912198041d0c6af7d327d1df022f6a21f2ce65395f8b5eeff47b475056e6d6debcdee65a220bc705ac235d1e10f25a47642b09bbcbe4509ffc1e621c61f2df88d2a9575692bf1fa8456060347e05fd3b41e369caecaa979c6c3d9fadac24385e871e73c907bf3d0a8d452f85c963e5230791e68e2d8264b854745f9f227b43c8f18e6f1d4060f96a227030880c6f8e2bccda5911bedceb5d2c65640fab851345932e35db4795a41d72ea0d0b4abcdfe0bfe237bf0ae087d517c03bed58bd115cf93c28f3c04a04879e449950043928e439a08e3e6708f1b5a7b99441270793f85f77299edbe8fbc3e4956f6cce8d6babf19939900c68b0dfb5e607ecd59ba7747868ad3495e727fac4daff7d69d9b0f72bc7d73c769bbf5af2135a4832ca205a936f322307ef510992987b8f712c388e72122b0bb633dcb12325d1121657649b7813a0f3952b37156918b65eccce34d0c1219cef72e9326f12920e983a46edfd30b572593e1657194e0c41d1e1830c55ac5dfc3e63dc69d9006eba308f0c85e66da89ddf81a65e6027b3144ea9e000e5d4e6f6354c405e0a47c7be23fd94bb38e7dd2f89e886212d9d6d76dafc173268716d3dc9a4fcca6f623a1df279418b147ea79b08c9eca5c723a949047690d84b6ddaebd2b69100f74d9e4323d15bb410c7dc77a74e646a9949a44a9ab2b697eedcbf060655ded990fdf157cf4ec3d7d1b6cdb50ecc27a3558660df90c993a32fb16771e9ba5f9cddb51edaa1b4592172a0daca839e09f55cf9ea1bb2659eddf52ec2ba75ac27b5c9e82524410f3a0886921235b22ee74319719d0c5b61f0e8dbd7de6533ba8a2e3d7e19ac6bf4036515ffc88ef3b02b85d8abad0e413bd56b1b4f404fa59b73cdc02cab7bf572565767b80ff87bd2bc2772349d122951b84248d406c4e1351d869c12430dc350b51896a0968867396293c7d267514e3fc80dafe5d578b6fbbbe015720942e46be881dd6ece5f131269e326b3be18292846d96cf9dc782d9b5ae8e44549ac9d3ce89347338c2949225bbdddfcf8faeb5cdbb7582fb66eec0cdfb3b21ffe61794a07a066080d1af3d90121a09c62583512a75df831bfbd4b039568197f683d0043d350b688dbe947c92b5cedcd7a64803791bd1a2dc6e0df0b9fb6a294d728e026dc9wb;
+
+unsigned g;
+
+_BitInt(6) foo (unsigned a, unsigned b, unsigned c,
+ unsigned _BitInt(256) z, unsigned _BitInt(12419) y) {
+ y /= b;
+ g -= MAX2 (n, a * y) % c;
+ return z;
+}
+#endif
+
+int main() {
+#if __BITINT_MAXWIDTH__ >= 12419
+ _BitInt(6) res = foo (0, 5, 5, 2, 0);
+ if (res != 2)
+ __builtin_abort ();
+#endif
+}
--
2.43.0