aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@orcam.me.uk>2025-01-12 16:48:54 +0000
committerMaciej W. Rozycki <macro@orcam.me.uk>2025-01-12 16:48:54 +0000
commited8cd42d138fa048e0c0eff1ea28b39f5abe1c29 (patch)
tree09fe9d2a8c897c6d488d40850c412c50121d7571 /gcc
parent4e557210b7f9fd669ff66c6958327eb2d4262d80 (diff)
downloadgcc-ed8cd42d138fa048e0c0eff1ea28b39f5abe1c29.zip
gcc-ed8cd42d138fa048e0c0eff1ea28b39f5abe1c29.tar.gz
gcc-ed8cd42d138fa048e0c0eff1ea28b39f5abe1c29.tar.bz2
Alpha: Fix a block move pessimisation with zero-extension after LDWU
For the BWX case we have a pessimisation in `alpha_expand_block_move' for HImode loads where we place the data loaded into a HImode register as well, therefore losing information that indeed the data loaded has already been zero-extended to the full DImode width of the register. Later on when we store this data in QImode quantities into an unaligned destination, we zero-extend it again for the purpose of right-shifting, such as with the test case included producing code at `-O2' as follows: ldah $2,unaligned_src_hi($29) !gprelhigh lda $1,unaligned_src_hi($2) !gprellow ldwu $6,unaligned_src_hi($2) !gprellow ldwu $5,2($1) ldwu $4,4($1) bis $31,$31,$31 zapnot $6,3,$3 # Redundant! ldbu $7,6($1) zapnot $5,3,$2 # Redundant! stb $6,0($16) zapnot $4,3,$1 # Redundant! stb $5,2($16) srl $3,8,$3 stb $4,4($16) srl $2,8,$2 stb $3,1($16) srl $1,8,$1 stb $2,3($16) stb $1,5($16) stb $7,6($16) The non-BWX case is unaffected, because there we use byte insertion, so we don't care that data is held in a HImode register. Address this by making the holding RTX a HImode subreg of the original DImode register, which the RTL passes can then see through and eliminate the zero-extension where otherwise required, resulting in this shortened code: ldah $2,unaligned_src_hi($29) !gprelhigh lda $1,unaligned_src_hi($2) !gprellow ldwu $4,unaligned_src_hi($2) !gprellow ldwu $3,2($1) ldwu $2,4($1) bis $31,$31,$31 srl $4,8,$6 ldbu $1,6($1) srl $3,8,$5 stb $4,0($16) stb $6,1($16) srl $2,8,$4 stb $3,2($16) stb $5,3($16) stb $2,4($16) stb $4,5($16) stb $1,6($16) While at it reformat the enclosing do-while statement according to the GNU Coding Standards, observing that in this case it does not obfuscate the change owing to the odd original indentation. gcc/ * config/alpha/alpha.cc (alpha_expand_block_move): Use a HImode subreg of a DImode register to hold data from an aligned HImode load.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/alpha/alpha.cc17
-rw-r--r--gcc/testsuite/gcc.target/alpha/memcpy-hi-unaligned-dst.c16
2 files changed, 27 insertions, 6 deletions
diff --git a/gcc/config/alpha/alpha.cc b/gcc/config/alpha/alpha.cc
index 8ec9e8c..6965ece 100644
--- a/gcc/config/alpha/alpha.cc
+++ b/gcc/config/alpha/alpha.cc
@@ -3999,14 +3999,19 @@ alpha_expand_block_move (rtx operands[])
if (bytes >= 2)
{
if (src_align >= 16)
- {
- do {
- data_regs[nregs++] = tmp = gen_reg_rtx (HImode);
- emit_move_insn (tmp, adjust_address (orig_src, HImode, ofs));
+ do
+ {
+ tmp = gen_reg_rtx (DImode);
+ emit_move_insn (tmp,
+ expand_simple_unop (DImode, SET,
+ adjust_address (orig_src,
+ HImode, ofs),
+ NULL_RTX, 1));
+ data_regs[nregs++] = gen_rtx_SUBREG (HImode, tmp, 0);
bytes -= 2;
ofs += 2;
- } while (bytes >= 2);
- }
+ }
+ while (bytes >= 2);
else if (! TARGET_BWX)
{
data_regs[nregs++] = tmp = gen_reg_rtx (HImode);
diff --git a/gcc/testsuite/gcc.target/alpha/memcpy-hi-unaligned-dst.c b/gcc/testsuite/gcc.target/alpha/memcpy-hi-unaligned-dst.c
new file mode 100644
index 0000000..4e3c02f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/alpha/memcpy-hi-unaligned-dst.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-mbwx" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+unsigned short unaligned_src_hi[4];
+
+void
+memcpy_unaligned_dst_hi (void *dst)
+{
+ __builtin_memcpy (dst, unaligned_src_hi, 7);
+}
+
+/* { dg-final { scan-assembler-times "\\sldwu\\s" 3 } } */
+/* { dg-final { scan-assembler-times "\\sldbu\\s" 1 } } */
+/* { dg-final { scan-assembler-times "\\sstb\\s" 7 } } */
+/* { dg-final { scan-assembler-not "\\szapnot\\s" } } */