diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index e6158f243c00676dbfd3c1a578966f1a0b6b4b42..08c425007a1b1366a85fd16dde33550b3937a40b 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -1261,7 +1261,13 @@ rtx gen_rtx_REG_offset (rtx reg, machine_mode mode, unsigned int regno, poly_int64 offset) { - rtx new_rtx = gen_rtx_REG (mode, regno); + /* Use gen_raw_REG rather than gen_rtx_REG, because otherwise we'd + overwrite REG_ATTRS (and in the callers often ORIGINAL_REGNO too) + of the shared REG rtxes like stack_pointer_rtx etc. This should + happen only for SUBREGs from DEBUG_INSNs, RA should ensure + multi-word registers don't overlap the special registers like + stack pointer. */ + rtx new_rtx = gen_raw_REG (mode, regno); update_reg_offset (new_rtx, reg, offset); return new_rtx; diff --git a/gcc/testsuite/gcc.dg/pr103808.c b/gcc/testsuite/gcc.dg/pr103808.c new file mode 100644 index 0000000000000000000000000000000000000000..51fc460a900873ed5a59e80668f04f0b4ae20451 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr103808.c @@ -0,0 +1,23 @@ +/* PR debug/103808 */ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-fcompare-debug -O2 -ftrapv" } */ + +void +foo (__int128 x, int y) +{ + for (;;) + { + __int128 a, b; + + x |= !!y; + a = x + 1; + b = y ? ++y : ++x; + y = a < b; + asm ("" : "+r" (y)); + if (x >> 2) + y *= 2; + + if (y == b) + __builtin_unreachable (); + } +}