Skip to content

Commit a27d5f9

Browse files
Matt ThomasMaciej W. Rozycki
Matt Thomas
authored and
Maciej W. Rozycki
committed
PR target/58901: reload: Handle SUBREG of MEM with a mode-dependent address
Fix an ICE with the handling of RTL expressions like: (subreg:QI (mem/c:SI (plus:SI (plus:SI (mult:SI (reg/v:SI 0 %r0 [orig:67 i ] [67]) (const_int 4 [0x4])) (reg/v/f:SI 7 %r7 [orig:59 doacross ] [59])) (const_int 40 [0x28])) [1 MEM[(unsigned int *)doacross_63 + 40B + i_106 * 4]+0 S4 A32]) 0) that causes the compilation of libgomp to fail: during RTL pass: reload .../libgomp/ordered.c: In function 'GOMP_doacross_wait': .../libgomp/ordered.c:507:1: internal compiler error: in change_address_1, at emit-rtl.c:2275 507 | } | ^ 0x10a3462b change_address_1 .../gcc/emit-rtl.c:2275 0x10a353a7 adjust_address_1(rtx_def*, machine_mode, poly_int<1u, long>, int, int, int, poly_int<1u, long>) .../gcc/emit-rtl.c:2409 0x10ae2993 alter_subreg(rtx_def**, bool) .../gcc/final.c:3368 0x10ae25cf cleanup_subreg_operands(rtx_insn*) .../gcc/final.c:3322 0x110922a3 reload(rtx_insn*, int) .../gcc/reload1.c:1232 0x10de2bf7 do_reload .../gcc/ira.c:5812 0x10de3377 execute .../gcc/ira.c:5986 in a `vax-netbsdelf' build, where an attempt is made to change the mode of the contained memory reference to the mode of the containing SUBREG. Such RTL expressions are produced by the VAX shift and rotate patterns (`ashift', `ashiftrt', `rotate', `rotatert') where the count operand always has the QI mode regardless of the mode, either SI or DI, of the datum shifted or rotated. Such a mode change cannot work where the memory reference uses the indexed addressing mode, where a multiplier is implied that in the VAX ISA depends on the width of the memory access requested and therefore changing the machine mode would change the address calculation as well. Avoid the attempt then by forcing the reload of any SUBREGs containing a mode-dependent memory reference, also fixing these regressions: FAIL: gcc.c-torture/compile/pr46883.c -Os (internal compiler error) FAIL: gcc.c-torture/compile/pr46883.c -Os (test for excess errors) FAIL: gcc.c-torture/execute/20120808-1.c -O2 (internal compiler error) FAIL: gcc.c-torture/execute/20120808-1.c -O2 (test for excess errors) FAIL: gcc.c-torture/execute/20120808-1.c -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions (internal compiler error) FAIL: gcc.c-torture/execute/20120808-1.c -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions (test for excess errors) FAIL: gcc.c-torture/execute/20120808-1.c -O3 -g (internal compiler error) FAIL: gcc.c-torture/execute/20120808-1.c -O3 -g (test for excess errors) FAIL: gcc.c-torture/execute/20120808-1.c -O2 -flto -fno-use-linker-plugin -flto-partition=none (internal compiler error) FAIL: gcc.c-torture/execute/20120808-1.c -O2 -flto -fno-use-linker-plugin -flto-partition=none (test for excess errors) FAIL: gcc.c-torture/execute/20120808-1.c -O2 -flto -fuse-linker-plugin -fno-fat-lto-objects (internal compiler error) FAIL: gcc.c-torture/execute/20120808-1.c -O2 -flto -fuse-linker-plugin -fno-fat-lto-objects (test for excess errors) FAIL: gcc.dg/20050629-1.c (internal compiler error) FAIL: gcc.dg/20050629-1.c (test for excess errors) FAIL: c-c++-common/torture/pr53505.c -Os (internal compiler error) FAIL: c-c++-common/torture/pr53505.c -Os (test for excess errors) FAIL: gfortran.dg/coarray_failed_images_1.f08 -Os (internal compiler error) FAIL: gfortran.dg/coarray_stopped_images_1.f08 -Os (internal compiler error) With test case #0 included it causes a reload with: (insn 15 14 16 4 (set (reg:SI 31) (ashift:SI (const_int 1 [0x1]) (subreg:QI (reg:SI 30 [ MEM[(int *)s_8(D) + 4B + _5 * 4] ]) 0))) "pr58901-0.c":15:12 94 {ashlsi3} (expr_list:REG_DEAD (reg:SI 30 [ MEM[(int *)s_8(D) + 4B + _5 * 4] ]) (nil))) as follows: Reloads for insn # 15 Reload 0: reload_in (SI) = (reg:SI 30 [ MEM[(int *)s_8(D) + 4B + _5 * 4] ]) ALL_REGS, RELOAD_FOR_INPUT (opnum = 2) reload_in_reg: (reg:SI 30 [ MEM[(int *)s_8(D) + 4B + _5 * 4] ]) reload_reg_rtx: (reg:SI 5 %r5) resulting in: (insn 37 14 15 4 (set (reg:SI 5 %r5) (mem/c:SI (plus:SI (plus:SI (mult:SI (reg/v:SI 1 %r1 [orig:25 i ] [25]) (const_int 4 [0x4])) (reg/v/f:SI 4 %r4 [orig:29 s ] [29])) (const_int 4 [0x4])) [1 MEM[(int *)s_8(D) + 4B + _5 * 4]+0 S4 A32])) "pr58901-0.c":15:12 12 {movsi_2} (nil)) (insn 15 37 16 4 (set (reg:SI 2 %r2 [31]) (ashift:SI (const_int 1 [0x1]) (reg:QI 5 %r5))) "pr58901-0.c":15:12 94 {ashlsi3} (nil)) and assembly like: .L3: movl 4(%r4)[%r1],%r5 ashl %r5,$1,%r2 xorl2 %r2,%r0 incl %r1 cmpl %r1,%r3 jneq .L3 produced for the loop, providing optimization has been enabled. Likewise with test case #1 the reload of: (insn 17 16 18 4 (set (reg:SI 34) (and:SI (subreg:SI (reg/v:DI 27 [ t ]) 4) (const_int 1 [0x1]))) "pr58901-1.c":18:20 77 {*andsi_const_int} (expr_list:REG_DEAD (reg/v:DI 27 [ t ]) (nil))) is as follows: Reloads for insn # 17 Reload 0: reload_in (DI) = (reg/v:DI 27 [ t ]) reload_out (SI) = (reg:SI 2 %r2 [34]) ALL_REGS, RELOAD_OTHER (opnum = 0) reload_in_reg: (reg/v:DI 27 [ t ]) reload_out_reg: (reg:SI 2 %r2 [34]) reload_reg_rtx: (reg:DI 4 %r4) resulting in: (insn 40 16 17 4 (set (reg:DI 4 %r4) (mem/c:DI (plus:SI (mult:SI (reg/v:SI 1 %r1 [orig:26 i ] [26]) (const_int 8 [0x8])) (reg/v/f:SI 3 %r3 [orig:30 s ] [30])) [1 MEM[(const struct s *)s_13(D) + _7 * 8]+0 S8 A32])) "pr58901-1.c":18:20 11 {movdi} (nil)) (insn 17 40 41 4 (set (reg:SI 4 %r4) (and:SI (reg:SI 5 %r5 [+4 ]) (const_int 1 [0x1]))) "pr58901-1.c":18:20 77 {*andsi_const_int} (nil)) and assembly like: .L3: movq (%r3)[%r1],%r4 bicl3 $-2,%r5,%r4 addl2 %r4,%r0 jaoblss %r0,%r1,.L3 First posted at: <https://gcc.gnu.org/ml/gcc/2014-06/msg00060.html>. 2020-12-05 Matt Thomas <[email protected]> Maciej W. Rozycki <[email protected]> gcc/ PR target/58901 * reload.c (push_reload): Also reload the inner expression of a SUBREG for pseudos associated with a mode-dependent memory reference. (find_reloads): Force a reload likewise. 2020-12-05 Maciej W. Rozycki <[email protected]> gcc/testsuite/ PR target/58901 * gcc.c-torture/compile/pr58901-0.c: New test. * gcc.c-torture/compile/pr58901-1.c: New test.
1 parent 4eb8f93 commit a27d5f9

File tree

3 files changed

+106
-36
lines changed

3 files changed

+106
-36
lines changed

gcc/reload.c

Lines changed: 68 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,53 +1043,72 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
10431043
Also reload the inner expression if it does not require a secondary
10441044
reload but the SUBREG does.
10451045
1046-
Finally, reload the inner expression if it is a register that is in
1046+
Also reload the inner expression if it is a register that is in
10471047
the class whose registers cannot be referenced in a different size
10481048
and M1 is not the same size as M2. If subreg_lowpart_p is false, we
10491049
cannot reload just the inside since we might end up with the wrong
10501050
register class. But if it is inside a STRICT_LOW_PART, we have
1051-
no choice, so we hope we do get the right register class there. */
1051+
no choice, so we hope we do get the right register class there.
1052+
1053+
Finally, reload the inner expression if it is a pseudo that will
1054+
become a MEM and the MEM has a mode-dependent address, as in that
1055+
case we obviously cannot change the mode of the MEM to that of the
1056+
containing SUBREG as that would change the interpretation of the
1057+
address. */
10521058

10531059
scalar_int_mode inner_mode;
10541060
if (in != 0 && GET_CODE (in) == SUBREG
1055-
&& (subreg_lowpart_p (in) || strict_low)
10561061
&& targetm.can_change_mode_class (GET_MODE (SUBREG_REG (in)),
10571062
inmode, rclass)
10581063
&& contains_allocatable_reg_of_mode[rclass][GET_MODE (SUBREG_REG (in))]
1059-
&& (CONSTANT_P (SUBREG_REG (in))
1060-
|| GET_CODE (SUBREG_REG (in)) == PLUS
1061-
|| strict_low
1062-
|| (((REG_P (SUBREG_REG (in))
1063-
&& REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER)
1064-
|| MEM_P (SUBREG_REG (in)))
1065-
&& (paradoxical_subreg_p (inmode, GET_MODE (SUBREG_REG (in)))
1066-
|| (known_le (GET_MODE_SIZE (inmode), UNITS_PER_WORD)
1067-
&& is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (in)),
1068-
&inner_mode)
1069-
&& GET_MODE_SIZE (inner_mode) <= UNITS_PER_WORD
1070-
&& paradoxical_subreg_p (inmode, inner_mode)
1071-
&& LOAD_EXTEND_OP (inner_mode) != UNKNOWN)
1072-
|| (WORD_REGISTER_OPERATIONS
1073-
&& partial_subreg_p (inmode, GET_MODE (SUBREG_REG (in)))
1074-
&& (known_equal_after_align_down
1075-
(GET_MODE_SIZE (inmode) - 1,
1076-
GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) - 1,
1077-
UNITS_PER_WORD)))))
1078-
|| (REG_P (SUBREG_REG (in))
1079-
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
1080-
/* The case where out is nonzero
1081-
is handled differently in the following statement. */
1082-
&& (out == 0 || subreg_lowpart_p (in))
1083-
&& (complex_word_subreg_p (inmode, SUBREG_REG (in))
1084-
|| !targetm.hard_regno_mode_ok (subreg_regno (in), inmode)))
1085-
|| (secondary_reload_class (1, rclass, inmode, in) != NO_REGS
1086-
&& (secondary_reload_class (1, rclass, GET_MODE (SUBREG_REG (in)),
1087-
SUBREG_REG (in))
1088-
== NO_REGS))
1064+
&& (strict_low
1065+
|| (subreg_lowpart_p (in)
1066+
&& (CONSTANT_P (SUBREG_REG (in))
1067+
|| GET_CODE (SUBREG_REG (in)) == PLUS
1068+
|| (((REG_P (SUBREG_REG (in))
1069+
&& REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER)
1070+
|| MEM_P (SUBREG_REG (in)))
1071+
&& (paradoxical_subreg_p (inmode,
1072+
GET_MODE (SUBREG_REG (in)))
1073+
|| (known_le (GET_MODE_SIZE (inmode), UNITS_PER_WORD)
1074+
&& is_a <scalar_int_mode> (GET_MODE (SUBREG_REG
1075+
(in)),
1076+
&inner_mode)
1077+
&& GET_MODE_SIZE (inner_mode) <= UNITS_PER_WORD
1078+
&& paradoxical_subreg_p (inmode, inner_mode)
1079+
&& LOAD_EXTEND_OP (inner_mode) != UNKNOWN)
1080+
|| (WORD_REGISTER_OPERATIONS
1081+
&& partial_subreg_p (inmode,
1082+
GET_MODE (SUBREG_REG (in)))
1083+
&& (known_equal_after_align_down
1084+
(GET_MODE_SIZE (inmode) - 1,
1085+
GET_MODE_SIZE (GET_MODE (SUBREG_REG
1086+
(in))) - 1,
1087+
UNITS_PER_WORD)))))
1088+
|| (REG_P (SUBREG_REG (in))
1089+
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
1090+
/* The case where out is nonzero
1091+
is handled differently in the following statement. */
1092+
&& (out == 0 || subreg_lowpart_p (in))
1093+
&& (complex_word_subreg_p (inmode, SUBREG_REG (in))
1094+
|| !targetm.hard_regno_mode_ok (subreg_regno (in),
1095+
inmode)))
1096+
|| (secondary_reload_class (1, rclass, inmode, in) != NO_REGS
1097+
&& (secondary_reload_class (1, rclass,
1098+
GET_MODE (SUBREG_REG (in)),
1099+
SUBREG_REG (in))
1100+
== NO_REGS))
1101+
|| (REG_P (SUBREG_REG (in))
1102+
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
1103+
&& !REG_CAN_CHANGE_MODE_P (REGNO (SUBREG_REG (in)),
1104+
GET_MODE (SUBREG_REG (in)),
1105+
inmode))))
10891106
|| (REG_P (SUBREG_REG (in))
1090-
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
1091-
&& !REG_CAN_CHANGE_MODE_P (REGNO (SUBREG_REG (in)),
1092-
GET_MODE (SUBREG_REG (in)), inmode))))
1107+
&& REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER
1108+
&& reg_equiv_mem (REGNO (SUBREG_REG (in)))
1109+
&& (mode_dependent_address_p
1110+
(XEXP (reg_equiv_mem (REGNO (SUBREG_REG (in))), 0),
1111+
MEM_ADDR_SPACE (reg_equiv_mem (REGNO (SUBREG_REG (in)))))))))
10931112
{
10941113
#ifdef LIMIT_RELOAD_CLASS
10951114
in_subreg_loc = inloc;
@@ -3157,6 +3176,19 @@ find_reloads (rtx_insn *insn, int replace, int ind_levels, int live_known,
31573176
&& paradoxical_subreg_p (operand_mode[i],
31583177
inner_mode)
31593178
&& LOAD_EXTEND_OP (inner_mode) != UNKNOWN)))
3179+
/* We must force a reload of a SUBREG's inner expression
3180+
if it is a pseudo that will become a MEM and the MEM
3181+
has a mode-dependent address, as in that case we
3182+
obviously cannot change the mode of the MEM to that
3183+
of the containing SUBREG as that would change the
3184+
interpretation of the address. */
3185+
|| (REG_P (operand)
3186+
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
3187+
&& reg_equiv_mem (REGNO (operand))
3188+
&& (mode_dependent_address_p
3189+
(XEXP (reg_equiv_mem (REGNO (operand)), 0),
3190+
(MEM_ADDR_SPACE
3191+
(reg_equiv_mem (REGNO (operand)))))))
31603192
)
31613193
force_reload = 1;
31623194
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
typedef int __attribute__ ((mode (SI))) int_t;
2+
3+
struct s
4+
{
5+
int_t n;
6+
int_t c[];
7+
};
8+
9+
int_t
10+
ashlsi (int_t x, const struct s *s)
11+
{
12+
int_t i;
13+
14+
for (i = 0; i < s->n; i++)
15+
x ^= 1 << s->c[i];
16+
return x;
17+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
typedef signed int __attribute__ ((mode (SI))) int_t;
2+
3+
struct s
4+
{
5+
int_t n;
6+
int_t m : 1;
7+
int_t l : 31;
8+
};
9+
10+
int_t
11+
movdi (int_t x, const struct s *s)
12+
{
13+
int_t i;
14+
15+
for (i = 0; i < x; i++)
16+
{
17+
const struct s t = s[i];
18+
x += t.m ? 1 : 0;
19+
}
20+
return x;
21+
}

0 commit comments

Comments
 (0)