summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>2022-06-15 16:07:20 +0100
committerRichard Earnshaw <rearnsha@arm.com>2022-06-16 09:25:16 +0100
commit723c1d6284ca9f79cc35bf7bf49f391417773f83 (patch)
treec763b9c19ca3ad37cbc5e9f27d4058a77ca7b550
parentDaily bump. (diff)
downloadgcc-723c1d6284ca9f79cc35bf7bf49f391417773f83.tar.gz
gcc-723c1d6284ca9f79cc35bf7bf49f391417773f83.tar.bz2
gcc-723c1d6284ca9f79cc35bf7bf49f391417773f83.tar.xz
arm: big-endian issue in gen_cpymem_ldrd_strd [PR105981]
The code in gen_cpymem_ldrd_strd has been incorrect for big-endian since r230663. The problem is that we use gen_lowpart, etc. to split the 64-bit quantity, but fail to account for the fact that these routines are really dealing with 64-bit /values/ and in big-endian the ordering of the sub-registers changes. To fix this, I've renamed the conceptually misnamed low_reg and hi_reg as first_reg and second_reg, and then used different logic for big-endian targets to initialize these values. This makes the logic clearer than trying to think about high bits and low bits. gcc/ChangeLog: PR target/105981 * config/arm/arm.cc (gen_cpymem_ldrd_strd): Rename low_reg and hi_reg to first_reg and second_reg respectively. Initialize them correctly when generating big-endian code. (cherry picked from commit 8aaa948059a8b5f0a62ad010d0aa6346b7ac9cd3)
-rw-r--r--gcc/config/arm/arm.cc24
1 files changed, 16 insertions, 8 deletions
diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc
index 14e2fdfeafa..d88086fbd13 100644
--- a/gcc/config/arm/arm.cc
+++ b/gcc/config/arm/arm.cc
@@ -15671,13 +15671,21 @@ gen_cpymem_ldrd_strd (rtx *operands)
15671 { 15671 {
15672 len -= 8; 15672 len -= 8;
15673 reg0 = gen_reg_rtx (DImode); 15673 reg0 = gen_reg_rtx (DImode);
15674 rtx low_reg = NULL_RTX; 15674 rtx first_reg = NULL_RTX;
15675 rtx hi_reg = NULL_RTX; 15675 rtx second_reg = NULL_RTX;
15676 15676
15677 if (!src_aligned || !dst_aligned) 15677 if (!src_aligned || !dst_aligned)
15678 { 15678 {
15679 low_reg = gen_lowpart (SImode, reg0); 15679 if (BYTES_BIG_ENDIAN)
15680 hi_reg = gen_highpart_mode (SImode, DImode, reg0); 15680 {
15681 second_reg = gen_lowpart (SImode, reg0);
15682 first_reg = gen_highpart_mode (SImode, DImode, reg0);
15683 }
15684 else
15685 {
15686 first_reg = gen_lowpart (SImode, reg0);
15687 second_reg = gen_highpart_mode (SImode, DImode, reg0);
15688 }
15681 } 15689 }
15682 if (MEM_ALIGN (src) >= 2 * BITS_PER_WORD) 15690 if (MEM_ALIGN (src) >= 2 * BITS_PER_WORD)
15683 emit_move_insn (reg0, src); 15691 emit_move_insn (reg0, src);
@@ -15685,9 +15693,9 @@ gen_cpymem_ldrd_strd (rtx *operands)
15685 emit_insn (gen_unaligned_loaddi (reg0, src)); 15693 emit_insn (gen_unaligned_loaddi (reg0, src));
15686 else 15694 else
15687 { 15695 {
15688 emit_insn (gen_unaligned_loadsi (low_reg, src)); 15696 emit_insn (gen_unaligned_loadsi (first_reg, src));
15689 src = next_consecutive_mem (src); 15697 src = next_consecutive_mem (src);
15690 emit_insn (gen_unaligned_loadsi (hi_reg, src)); 15698 emit_insn (gen_unaligned_loadsi (second_reg, src));
15691 } 15699 }
15692 15700
15693 if (MEM_ALIGN (dst) >= 2 * BITS_PER_WORD) 15701 if (MEM_ALIGN (dst) >= 2 * BITS_PER_WORD)
@@ -15696,9 +15704,9 @@ gen_cpymem_ldrd_strd (rtx *operands)
15696 emit_insn (gen_unaligned_storedi (dst, reg0)); 15704 emit_insn (gen_unaligned_storedi (dst, reg0));
15697 else 15705 else
15698 { 15706 {
15699 emit_insn (gen_unaligned_storesi (dst, low_reg)); 15707 emit_insn (gen_unaligned_storesi (dst, first_reg));
15700 dst = next_consecutive_mem (dst); 15708 dst = next_consecutive_mem (dst);
15701 emit_insn (gen_unaligned_storesi (dst, hi_reg)); 15709 emit_insn (gen_unaligned_storesi (dst, second_reg));
15702 } 15710 }
15703 15711
15704 src = next_consecutive_mem (src); 15712 src = next_consecutive_mem (src);