diff --git a/gcc/config/alpha/alpha.cc b/gcc/config/alpha/alpha.cc index 07753297c3875574fb289a6cac3370ecc88763ca..3b3a237a955fa7d6ab4b6220cbe061de71a59d6e 100644 --- a/gcc/config/alpha/alpha.cc +++ b/gcc/config/alpha/alpha.cc @@ -3771,6 +3771,78 @@ alpha_expand_unaligned_store_words (rtx *data_regs, rtx dmem, emit_move_insn (st_addr_1, st_tmp_1); } +/* Get the base alignment and offset of EXPR in A and O respectively. + Check for any pseudo register pointer alignment and for any tree + node information and return the largest alignment determined and + its associated offset. */ + +static void +alpha_get_mem_rtx_alignment_and_offset (rtx expr, int &a, HOST_WIDE_INT &o) +{ + HOST_WIDE_INT tree_offset = 0, reg_offset = 0, mem_offset = 0; + int tree_align = 0, reg_align = 0, mem_align = MEM_ALIGN (expr); + + gcc_assert (MEM_P (expr)); + + rtx addr = XEXP (expr, 0); + switch (GET_CODE (addr)) + { + case REG: + reg_align = REGNO_POINTER_ALIGN (REGNO (addr)); + break; + + case PLUS: + if (REG_P (XEXP (addr, 0)) && CONST_INT_P (XEXP (addr, 1))) + { + reg_offset = INTVAL (XEXP (addr, 1)); + reg_align = REGNO_POINTER_ALIGN (REGNO (XEXP (addr, 0))); + } + break; + + default: + break; + } + + tree mem = MEM_EXPR (expr); + if (mem != NULL_TREE) + switch (TREE_CODE (mem)) + { + case MEM_REF: + tree_offset = mem_ref_offset (mem).force_shwi (); + tree_align = get_object_alignment (get_base_address (mem)); + break; + + case COMPONENT_REF: + { + tree byte_offset = component_ref_field_offset (mem); + tree bit_offset = DECL_FIELD_BIT_OFFSET (TREE_OPERAND (mem, 1)); + poly_int64 offset; + if (!byte_offset + || !poly_int_tree_p (byte_offset, &offset) + || !tree_fits_shwi_p (bit_offset)) + break; + tree_offset = offset + tree_to_shwi (bit_offset) / BITS_PER_UNIT; + } + tree_align = get_object_alignment (get_base_address (mem)); + break; + + default: + break; + } + + if (reg_align > mem_align) + { + mem_offset = reg_offset; + mem_align = reg_align; + } + if (tree_align > mem_align) + { + mem_offset = tree_offset; + mem_align = tree_align; + } + o = mem_offset; + a = mem_align; +} /* Expand string/block move operations. @@ -3799,27 +3871,19 @@ alpha_expand_block_move (rtx operands[]) else if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD) return 0; - /* Look for additional alignment information from recorded register info. */ + /* Look for stricter alignment. */ + HOST_WIDE_INT c; + int a; - tmp = XEXP (orig_src, 0); - if (REG_P (tmp)) - src_align = MAX (src_align, REGNO_POINTER_ALIGN (REGNO (tmp))); - else if (GET_CODE (tmp) == PLUS - && REG_P (XEXP (tmp, 0)) - && CONST_INT_P (XEXP (tmp, 1))) + alpha_get_mem_rtx_alignment_and_offset (orig_src, a, c); + if (a > src_align) { - unsigned HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1)); - unsigned int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0))); - - if (a > src_align) - { - if (a >= 64 && c % 8 == 0) - src_align = 64; - else if (a >= 32 && c % 4 == 0) - src_align = 32; - else if (a >= 16 && c % 2 == 0) - src_align = 16; - } + if (a >= 64 && c % 8 == 0) + src_align = 64; + else if (a >= 32 && c % 4 == 0) + src_align = 32; + else if (a >= 16 && c % 2 == 0) + src_align = 16; if (MEM_P (orig_src) && MEM_ALIGN (orig_src) < src_align) { @@ -3828,25 +3892,15 @@ alpha_expand_block_move (rtx operands[]) } } - tmp = XEXP (orig_dst, 0); - if (REG_P (tmp)) - dst_align = MAX (dst_align, REGNO_POINTER_ALIGN (REGNO (tmp))); - else if (GET_CODE (tmp) == PLUS - && REG_P (XEXP (tmp, 0)) - && CONST_INT_P (XEXP (tmp, 1))) + alpha_get_mem_rtx_alignment_and_offset (orig_dst, a, c); + if (a > dst_align) { - unsigned HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1)); - unsigned int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0))); - - if (a > dst_align) - { - if (a >= 64 && c % 8 == 0) - dst_align = 64; - else if (a >= 32 && c % 4 == 0) - dst_align = 32; - else if (a >= 16 && c % 2 == 0) - dst_align = 16; - } + if (a >= 64 && c % 8 == 0) + dst_align = 64; + else if (a >= 32 && c % 4 == 0) + dst_align = 32; + else if (a >= 16 && c % 2 == 0) + dst_align = 16; if (MEM_P (orig_dst) && MEM_ALIGN (orig_dst) < dst_align) { @@ -4048,7 +4102,6 @@ alpha_expand_block_clear (rtx operands[]) HOST_WIDE_INT align = INTVAL (align_rtx) * BITS_PER_UNIT; HOST_WIDE_INT alignofs = 0; rtx orig_dst = operands[0]; - rtx tmp; int i, words, ofs = 0; if (orig_bytes <= 0) @@ -4057,25 +4110,18 @@ alpha_expand_block_clear (rtx operands[]) return 0; /* Look for stricter alignment. */ - tmp = XEXP (orig_dst, 0); - if (REG_P (tmp)) - align = MAX (align, REGNO_POINTER_ALIGN (REGNO (tmp))); - else if (GET_CODE (tmp) == PLUS - && REG_P (XEXP (tmp, 0)) - && CONST_INT_P (XEXP (tmp, 1))) - { - HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1)); - int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0))); - - if (a > align) - { - if (a >= 64) - align = a, alignofs = 8 - c % 8; - else if (a >= 32) - align = a, alignofs = 4 - c % 4; - else if (a >= 16) - align = a, alignofs = 2 - c % 2; - } + HOST_WIDE_INT c; + int a; + + alpha_get_mem_rtx_alignment_and_offset (orig_dst, a, c); + if (a > align) + { + if (a >= 64) + align = a, alignofs = -c & 7; + else if (a >= 32) + align = a, alignofs = -c & 3; + else if (a >= 16) + align = a, alignofs = -c & 1; if (MEM_P (orig_dst) && MEM_ALIGN (orig_dst) < align) { diff --git a/gcc/testsuite/gcc.target/alpha/memclr-a2-o1-c9-ptr.c b/gcc/testsuite/gcc.target/alpha/memclr-a2-o1-c9-ptr.c index 06d0f0beffbc7f8e25304ef91bf79d7eacd7dd3b..3f7edc890e4435c8f5af254fc7a94a712f526fb2 100644 --- a/gcc/testsuite/gcc.target/alpha/memclr-a2-o1-c9-ptr.c +++ b/gcc/testsuite/gcc.target/alpha/memclr-a2-o1-c9-ptr.c @@ -43,8 +43,8 @@ memclr_a2_o1_c9 (u_t *u) that is with a byte store at offset 1 and with two unaligned load/store pairs at offsets 2 and 9 each. */ -/* { dg-final { scan-assembler-times "\\sldq_u\\s\\\$\[0-9\]+,2\\\(\\\$16\\\)\\s" 1 { xfail *-*-* } } } */ -/* { dg-final { scan-assembler-times "\\sldq_u\\s\\\$\[0-9\]+,9\\\(\\\$16\\\)\\s" 1 { xfail *-*-* } } } */ -/* { dg-final { scan-assembler-times "\\sstb\\s\\\$31,1\\\(\\\$16\\\)\\s" 1 { xfail *-*-* } } } */ -/* { dg-final { scan-assembler-times "\\sstq_u\\s\\\$\[0-9\]+,2\\\(\\\$16\\\)\\s" 1 { xfail *-*-* } } } */ -/* { dg-final { scan-assembler-times "\\sstq_u\\s\\\$\[0-9\]+,9\\\(\\\$16\\\)\\s" 1 { xfail *-*-* } } } */ +/* { dg-final { scan-assembler-times "\\sldq_u\\s\\\$\[0-9\]+,2\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sldq_u\\s\\\$\[0-9\]+,9\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstb\\s\\\$31,1\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstq_u\\s\\\$\[0-9\]+,2\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstq_u\\s\\\$\[0-9\]+,9\\\(\\\$16\\\)\\s" 1 } } */ diff --git a/gcc/testsuite/gcc.target/alpha/memcpy-di-aligned.c b/gcc/testsuite/gcc.target/alpha/memcpy-di-aligned.c new file mode 100644 index 0000000000000000000000000000000000000000..fd3c2b90c572b21937313b6f161a158cf36619d8 --- /dev/null +++ b/gcc/testsuite/gcc.target/alpha/memcpy-di-aligned.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +unsigned long aligned_src_di[9] = { [0 ... 8] = 0xe6e7e8e9eaebeced }; +unsigned long aligned_dst_di[9] = { [0 ... 8] = 0xdcdbdad9d8d7d6d5 }; + +void +memcpy_aligned_data_di (void) +{ + __builtin_memcpy (aligned_dst_di + 1, aligned_src_di + 1, 56); +} + +/* { dg-final { scan-assembler-times "\\sldq\\s" 7 } } */ +/* { dg-final { scan-assembler-times "\\sstq\\s" 7 } } */ +/* { dg-final { scan-assembler-not "\\s(?:ldq_u|stq_u)\\s" } } */ diff --git a/gcc/testsuite/gcc.target/alpha/memcpy-di-unaligned-dst.c b/gcc/testsuite/gcc.target/alpha/memcpy-di-unaligned-dst.c new file mode 100644 index 0000000000000000000000000000000000000000..5e9b5c32e52c3231cf5431c9cc0bc91c2904cd42 --- /dev/null +++ b/gcc/testsuite/gcc.target/alpha/memcpy-di-unaligned-dst.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +unsigned long unaligned_src_di[9] = { [0 ... 8] = 0xfefdfcfbfaf9f8f7 }; + +void +memcpy_unaligned_dst_di (void *dst) +{ + __builtin_memcpy (dst, unaligned_src_di + 1, 56); +} + +/* { dg-final { scan-assembler-times "\\sldq\\s" 7 } } */ +/* { dg-final { scan-assembler-times "\\sldq_u\\s" 2 } } */ +/* { dg-final { scan-assembler-times "\\sstq_u\\s" 8 } } */ +/* { dg-final { scan-assembler-not "\\sstq\\s" } } */ diff --git a/gcc/testsuite/gcc.target/alpha/memcpy-di-unaligned-src.c b/gcc/testsuite/gcc.target/alpha/memcpy-di-unaligned-src.c new file mode 100644 index 0000000000000000000000000000000000000000..912fa56dcc00e01c19726205f00a97f38d862d38 --- /dev/null +++ b/gcc/testsuite/gcc.target/alpha/memcpy-di-unaligned-src.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +unsigned long unaligned_dst_di[9] = { [0 ... 8] = 0xc4c5c6c7c8c9cacb }; + +void +memcpy_unaligned_src_di (const void *src) +{ + __builtin_memcpy (unaligned_dst_di + 1, src, 56); +} + +/* { dg-final { scan-assembler-times "\\sstq\\s" 7 } } */ +/* { dg-final { scan-assembler-times "\\sldq_u\\s" 8 } } */ +/* { dg-final { scan-assembler-not "\\s(?:ldq|stq_u)\\s" } } */ diff --git a/gcc/testsuite/gcc.target/alpha/memcpy-di-unaligned.c b/gcc/testsuite/gcc.target/alpha/memcpy-di-unaligned.c new file mode 100644 index 0000000000000000000000000000000000000000..fe7fc9b1d17d00ba5a2becf6eca286da640b8ea6 --- /dev/null +++ b/gcc/testsuite/gcc.target/alpha/memcpy-di-unaligned.c @@ -0,0 +1,51 @@ +/* { dg-do run } */ +/* { dg-additional-sources memcpy-di-aligned.c } */ +/* { dg-additional-sources memcpy-di-unaligned-src.c } */ +/* { dg-additional-sources memcpy-di-unaligned-dst.c } */ +/* { dg-options "" } */ + +void memcpy_aligned_data_di (void); +void memcpy_unaligned_dst_di (void *); +void memcpy_unaligned_src_di (const void *); + +extern unsigned long aligned_src_di[]; +extern unsigned long aligned_dst_di[]; +extern unsigned long unaligned_src_di[]; +extern unsigned long unaligned_dst_di[]; + +int +main (void) +{ + unsigned long v; + int i; + + for (i = 1, v = 0x0807060504030201; i < 8; i++, v += 0x0808080808080808) + unaligned_src_di[i] = v; + asm ("" : : : "memory"); + memcpy_unaligned_dst_di (aligned_src_di + 1); + asm ("" : : : "memory"); + memcpy_aligned_data_di (); + asm ("" : : : "memory"); + memcpy_unaligned_src_di (aligned_dst_di + 1); + asm ("" : : : "memory"); + for (i = 1, v = 0x0807060504030201; i < 8; i++, v += 0x0808080808080808) + if (unaligned_dst_di[i] != v) + return 1; + if (unaligned_src_di[0] != 0xfefdfcfbfaf9f8f7) + return 1; + if (unaligned_src_di[8] != 0xfefdfcfbfaf9f8f7) + return 1; + if (aligned_src_di[0] != 0xe6e7e8e9eaebeced) + return 1; + if (aligned_src_di[8] != 0xe6e7e8e9eaebeced) + return 1; + if (aligned_dst_di[0] != 0xdcdbdad9d8d7d6d5) + return 1; + if (aligned_dst_di[8] != 0xdcdbdad9d8d7d6d5) + return 1; + if (unaligned_dst_di[0] != 0xc4c5c6c7c8c9cacb) + return 1; + if (unaligned_dst_di[8] != 0xc4c5c6c7c8c9cacb) + return 1; + return 0; +}