https://gcc.gnu.org/g:da293ec6b68fab23c44f6643011cf7ae62d93b16
commit r16-4439-gda293ec6b68fab23c44f6643011cf7ae62d93b16 Author: Roger Sayle <[email protected]> Date: Wed Oct 15 11:21:18 2025 +0100 PR rtl-optimization/122266: Handle TImode in reg_num_sign_bit_copies_for_combine This patch resolves PR rtl-optimization/122266 by changing the types of the last_set_sign_bit_copies and sign_bit_copies fields in combine.cc's reg_stat_type struct to be "unsigned short". This makes both types consistent, and fixes the issue that on platforms where char is by default signed, combine.cc can overflow when handling TImode values, where sign_bit_copies can be 128 bits. Conveniently, there are holes (caused by field alignment/padding) in the reg_stat_type struct that allows us to upgrade to "unsigned short" without increasing the total size of the struct. This should help reduce problems in future handling OImode or XImode values, or possible issues with 256-bit and 512-bit vector modes. Note that it's important to take care when reordering the fields of this struct, as the (partial) ordering of fields is significant: See the use of offsetof in combine.cc's init_reg_last. Before: (gdb) ptype /o reg_stat_type /* offset | size */ type = struct reg_stat_type { /* 0 | 8 */ rtx_insn *last_death; /* 8 | 8 */ rtx_insn *last_set; /* 16 | 8 */ rtx last_set_value; /* 24 | 4 */ int last_set_table_tick; /* 28 | 4 */ int last_set_label; /* 32 | 8 */ unsigned long last_set_nonzero_bits; /* 40 | 1 */ char last_set_sign_bit_copies; /* 41: 0 | 4 */ machine_mode last_set_mode : 16; /* 43 | 1 */ bool last_set_invalid; /* 44 | 1 */ unsigned char sign_bit_copies; /* XXX 3-byte hole */ /* 48 | 8 */ unsigned long nonzero_bits; /* 56 | 4 */ int truncation_label; /* 60: 0 | 4 */ machine_mode truncated_to_mode : 16; /* XXX 2-byte padding */ /* total size (bytes): 64 */ } After: /* offset | size */ type = struct reg_stat_type { /* 0 | 8 */ rtx_insn *last_death; /* 8 | 8 */ rtx_insn *last_set; /* 16 | 8 */ rtx last_set_value; /* 24 | 4 */ int last_set_table_tick; /* 28 | 4 */ int last_set_label; /* 32 | 8 */ unsigned long last_set_nonzero_bits; /* 40 | 2 */ unsigned short last_set_sign_bit_copies; /* 42: 0 | 4 */ machine_mode last_set_mode : 16; /* 44 | 1 */ bool last_set_invalid; /* XXX 1-byte hole */ /* 46 | 2 */ unsigned short sign_bit_copies; /* 48 | 8 */ unsigned long nonzero_bits; /* 56 | 4 */ int truncation_label; /* 60: 0 | 4 */ machine_mode truncated_to_mode : 16; /* XXX 2-byte padding */ /* total size (bytes): 64 */ } 2025-10-15 Roger Sayle <[email protected]> gcc/ChangeLog PR rtl-optimization/122266 * combine.cc (struct reg_stat_type): Change types of sign_bit_copies and last_set_sign_bit_copies to unsigned short, to avoid overflows on TImode (and wider) values. gcc/testsuite/ChangeLog PR rtl-optimization/122266 * gcc.target/i386/pr122266.c: New test case. Diff: --- gcc/combine.cc | 4 ++-- gcc/testsuite/gcc.target/i386/pr122266.c | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/gcc/combine.cc b/gcc/combine.cc index 4dbc1f6a4a4e..66963222efcd 100644 --- a/gcc/combine.cc +++ b/gcc/combine.cc @@ -195,7 +195,7 @@ struct reg_stat_type { sign bits copies it was known to have when it was last set. */ unsigned HOST_WIDE_INT last_set_nonzero_bits; - char last_set_sign_bit_copies; + unsigned short last_set_sign_bit_copies; ENUM_BITFIELD(machine_mode) last_set_mode : MACHINE_MODE_BITSIZE; /* Set to true if references to register n in expressions should not be @@ -216,7 +216,7 @@ struct reg_stat_type { If an entry is zero, it means that we don't know anything special. */ - unsigned char sign_bit_copies; + unsigned short sign_bit_copies; unsigned HOST_WIDE_INT nonzero_bits; diff --git a/gcc/testsuite/gcc.target/i386/pr122266.c b/gcc/testsuite/gcc.target/i386/pr122266.c new file mode 100644 index 000000000000..4e31a6aa8325 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr122266.c @@ -0,0 +1,10 @@ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2" } */ + +signed __int128 foo(signed __int128 x) { + signed __int128 t = x >> 127; + return ((x^t)>>1)^t; +} + +/* { dg-final { scan-assembler-times "xorq" 4 } } */ +/* { dg-final { scan-assembler-times "sarq" 2 } } */
