From 9c769a65e92b891c96d6f9088b55a450164964c3 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 6 Jul 2015 16:21:55 +0000 Subject: [PATCH] [ARM] fix movdi expander to avoid illegal ldrd/strd * config/arm/arm.md (movdi): Avoid odd-number ldrd/strd in ARM state. From-SVN: r225461 --- gcc/ChangeLog | 4 ++++ gcc/config/arm/arm.md | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d3929fa41f6..82755498c17 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2015-07-06 Alan Lawrence + + * config/arm/arm.md (movdi): Avoid odd-number ldrd/strd in ARM state. + 2015-07-06 Richard Biener PR tree-optimization/66772 diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 1ac8af099ce..be51c77dd8e 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -5481,6 +5481,42 @@ if (!REG_P (operands[0])) operands[1] = force_reg (DImode, operands[1]); } + if (REG_P (operands[0]) && REGNO (operands[0]) < FIRST_VIRTUAL_REGISTER + && !HARD_REGNO_MODE_OK (REGNO (operands[0]), DImode)) + { + /* Avoid LDRD's into an odd-numbered register pair in ARM state + when expanding function calls. */ + gcc_assert (can_create_pseudo_p ()); + if (MEM_P (operands[1]) && MEM_VOLATILE_P (operands[1])) + { + /* Perform load into legal reg pair first, then move. */ + rtx reg = gen_reg_rtx (DImode); + emit_insn (gen_movdi (reg, operands[1])); + operands[1] = reg; + } + emit_move_insn (gen_lowpart (SImode, operands[0]), + gen_lowpart (SImode, operands[1])); + emit_move_insn (gen_highpart (SImode, operands[0]), + gen_highpart (SImode, operands[1])); + DONE; + } + else if (REG_P (operands[1]) && REGNO (operands[1]) < FIRST_VIRTUAL_REGISTER + && !HARD_REGNO_MODE_OK (REGNO (operands[1]), DImode)) + { + /* Avoid STRD's from an odd-numbered register pair in ARM state + when expanding function prologue. */ + gcc_assert (can_create_pseudo_p ()); + rtx split_dest = (MEM_P (operands[0]) && MEM_VOLATILE_P (operands[0])) + ? gen_reg_rtx (DImode) + : operands[0]; + emit_move_insn (gen_lowpart (SImode, split_dest), + gen_lowpart (SImode, operands[1])); + emit_move_insn (gen_highpart (SImode, split_dest), + gen_highpart (SImode, operands[1])); + if (split_dest != operands[0]) + emit_insn (gen_movdi (operands[0], split_dest)); + DONE; + } " )