ARM's neon_vector_mem_operand does not allow eliminable or virtual registers to be used as addresses. create_*_operand was supposed to cope with that by replacing the address with a (non-virtual) pseudo register. The problem is that I used the wrong function: force_reg rather than copy_to_mode_reg. I see I also rather lazily used Pmode instead of addr_space.address_mode. This patch fixes both problems.
Tested on arm-linux-gnueabi, where it prevents an ICE in dilayout.c. OK to install? Richard gcc/ PR middle-end/50873 * optabs.c (maybe_legitimize_operand_same_code): Use copy_to_mode_reg instead of force_reg. Do nothing if the address is already a non-virtual pseudo register. Index: gcc/optabs.c =================================================================== *** gcc/optabs.c 2011-12-08 11:17:35.319229272 +0000 --- gcc/optabs.c 2011-12-09 16:32:01.781886061 +0000 *************** maybe_legitimize_operand_same_code (enum *** 8241,8264 **** return true; /* If the operand is a memory whose address has no side effects, ! try forcing the address into a register. The check for side ! effects is important because force_reg cannot handle things ! like auto-modified addresses. */ ! if (insn_data[(int) icode].operand[opno].allows_mem ! && MEM_P (op->value) ! && !side_effects_p (XEXP (op->value, 0))) { ! rtx addr, mem, last; ! last = get_last_insn (); ! addr = force_reg (Pmode, XEXP (op->value, 0)); ! mem = replace_equiv_address (op->value, addr); ! if (insn_operand_matches (icode, opno, mem)) { ! op->value = mem; ! return true; } - delete_insns_since (last); } return false; --- 8241,8271 ---- return true; /* If the operand is a memory whose address has no side effects, ! try forcing the address into a non-virtual pseudo register. ! The check for side effects is important because copy_to_mode_reg ! cannot handle things like auto-modified addresses. */ ! if (insn_data[(int) icode].operand[opno].allows_mem && MEM_P (op->value)) { ! rtx addr, mem; ! mem = op->value; ! addr = XEXP (mem, 0); ! if (!(REG_P (addr) && REGNO (addr) > LAST_VIRTUAL_REGISTER) ! && !side_effects_p (addr)) { ! rtx last; ! enum machine_mode mode; ! ! last = get_last_insn (); ! mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem)); ! mem = replace_equiv_address (mem, copy_to_mode_reg (mode, addr)); ! if (insn_operand_matches (icode, opno, mem)) ! { ! op->value = mem; ! return true; ! } ! delete_insns_since (last); } } return false;