https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82192
--- Comment #13 from Jakub Jelinek <jakub at gcc dot gnu.org> --- So like this (untested) or somewhere else? --- gcc/combine.c.jj 2017-09-14 10:04:56.000000000 +0200 +++ gcc/combine.c 2017-09-14 16:59:28.529783572 +0200 @@ -7444,7 +7444,14 @@ make_extraction (machine_mode mode, rtx if (pos_rtx && CONST_INT_P (pos_rtx)) pos = INTVAL (pos_rtx), pos_rtx = 0; - if (GET_CODE (inner) == SUBREG && subreg_lowpart_p (inner)) + if (GET_CODE (inner) == SUBREG + && subreg_lowpart_p (inner) + && (paradoxical_subreg_p (inner) + /* If trying or potentionally trying to extract + bits outside of is_mode, don't look through + non-paradoxical SUBREGs. See PR82192. */ + || (pos_rtx == NULL_RTX + && pos + len <= GET_MODE_PRECISION (is_mode)))) { /* If going from (subreg:SI (mem:QI ...)) to (mem:QI ...), consider just the QI as the memory to extract from. @@ -7470,7 +7477,12 @@ make_extraction (machine_mode mode, rtx if (new_rtx != 0) return gen_rtx_ASHIFT (mode, new_rtx, XEXP (inner, 1)); } - else if (GET_CODE (inner) == TRUNCATE) + else if (GET_CODE (inner) == TRUNCATE + /* If trying or potentionally trying to extract + bits outside of is_mode, don't look through + TRUNCATE. See PR82192. */ + && pos_rtx == NULL_RTX + && pos + len <= GET_MODE_PRECISION (is_mode)) inner = XEXP (inner, 0); inner_mode = GET_MODE (inner); --- gcc/testsuite/gcc.c-torture/execute/pr82192.c.jj 2017-09-14 17:02:54.281234432 +0200 +++ gcc/testsuite/gcc.c-torture/execute/pr82192.c 2017-09-14 17:02:39.000000000 +0200 @@ -0,0 +1,22 @@ +/* PR rtl-optimization/82192 */ + +unsigned long long int a = 0x95dd3d896f7422e2ULL; +struct S { unsigned int m : 13; } b; + +__attribute__((noinline, noclone)) void +foo (void) +{ + b.m = ((unsigned) a) >> (0x644eee9667723bf7LL + | a & ~0xdee27af8U) - 0x644eee9667763bd8LL; +} + +int +main () +{ + if (__INT_MAX__ != 0x7fffffffULL) + return 0; + foo (); + if (b.m != 0) + __builtin_abort (); + return 0; +}