Hello, I've looked into RTL after register allocation. Insn which lead to assert is: (insn 77 180 79 4 (set (reg/v:TF 44 loc12 [orig:359 T8 ] [359]) (mem:TF (post_modify:DI (reg/f:DI 14 r14 [435]) (plus:DI (reg/f:DI 14 r14 [435]) (reg:DI 45 loc13 [orig:342 D.3347 ] [342]))) [2 *R1_102+0 S16 A128])) 1.i:2370 131 {*movtf_intern\ al}
When trying to split it into two DI loads here: ia64_split_tmode_move We check if source and destination RTX are register overlapped, and if so, set flag that says that load adress is dead after insns: if (GET_CODE (operands[1]) == MEM && reg_overlap_mentioned_p (operands[0], operands[1])) ... dead = true; This flags is asserted (to be unset) later in splitting of memory operand in ia64_split_tmode: case POST_MODIFY: gcc_assert (!reversed && !dead); I think that the insn (although op[0] and op1[1] are overlapped by regs) is still safe to split. And we might end up with something like this: (insn 272 0 0 (set (reg:DI 44 loc12) (mem:DI (post_inc:DI (reg/f:DI 14 r14 [435])) [2 *R1_102+0 S8 A128])) (insn 273 272 0 (set (reg:DI 45 loc13) (mem:DI (post_modify:DI (reg/f:DI 14 r14 [435]) (plus:DI (reg/f:DI 14 r14 [435]) (reg:DI 45 loc13 [orig:342 D.3347 ] [342]))) [2 *R1_102+8 S8 A64])) (set (reg/f:DI 14 r14 [435]) (plus:DI (reg/f:DI 14 r14 [435]) (const_int -8 [0xfffffffffffffff8]))) As far as I understand, second insn will update loc13 *after* ld is executed, so value of location in r14 will be correct. Patch in the bottom. ChangeLog entry: * config/ia64/ia64.c (ia64_split_tmode_move): Relax `dead' flag setting. Testcase builds w/o ICE with the patch. Bootstrapped. Could you pls take a look? -- Thanks, K --- gcc/config/ia64/ia64.c | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index a128b19..446ee59 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -1527,12 +1527,19 @@ ia64_split_tmode_move (rtx operands[]) && reg_overlap_mentioned_p (operands[0], operands[1])) { rtx base = XEXP (operands[1], 0); + rtx first_write = gen_rtx_REG (DImode, REGNO (operands[0])); while (GET_CODE (base) != REG) base = XEXP (base, 0); if (REGNO (base) == REGNO (operands[0])) - reversed = true; - dead = true; + { + reversed = true; + first_write = gen_rtx_REG (DImode, REGNO (operands[0]) + 1); + } + + if (GET_CODE (operands[0]) == REG + && reg_overlap_mentioned_p (first_write, operands[1])) + dead = true; } /* Another reason to do the moves in reversed order is if the first element of the target register pair is also the second element of