Skip to content

Commit 4a97237

Browse files
ptomsichKonstantinos Eleftheriou
andcommitted
ext-dce: narrow sign-extending loads to zero-extending when upper bits are dead
The ext-dce pass tracks bit-level liveness and can replace sign extensions with zero extensions when the upper bits are dead. However, ext_dce_try_optimize_extension bails out when the inner operand is MEM rather than REG, missing the opportunity to narrow sign-extending loads (e.g. lh -> lhu on RISC-V, ldrsh -> ldrh on AArch64). Add handling for SIGN_EXTEND of MEM: when the liveness analysis has already determined the sign bits are dead, replace the sign-extending load with a zero-extending load via validate_change, which ensures the target has a matching instruction pattern. gcc/ChangeLog: * ext-dce.cc (ext_dce_try_optimize_extension): Handle SIGN_EXTEND of MEM by replacing with ZERO_EXTEND of MEM when upper bits are dead. gcc/testsuite/ChangeLog: * gcc.target/aarch64/ext-dce-1.c: New test. * gcc.target/riscv/ext-dce-3.c: New test. * gcc.target/riscv/ext-dce-4.c: New test. Co-authored-by: Konstantinos Eleftheriou <konstantinos.eleftheriou@vrull.eu>
1 parent dcba59a commit 4a97237

4 files changed

Lines changed: 195 additions & 0 deletions

File tree

gcc/ext-dce.cc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,52 @@ ext_dce_try_optimize_extension (rtx_insn *insn, rtx set)
487487
rtx src = SET_SRC (set);
488488
rtx inner = XEXP (src, 0);
489489

490+
/* For sign-extending loads from memory, try to replace with a
491+
zero-extending load when the upper bits are dead. E.g. on RISC-V
492+
this turns lh+zext.h into just lhu. */
493+
if (MEM_P (inner) && GET_CODE (src) == SIGN_EXTEND)
494+
{
495+
if (dump_file)
496+
{
497+
fprintf (dump_file, "Processing insn:\n");
498+
dump_insn_slim (dump_file, insn);
499+
fprintf (dump_file, "Trying to narrow sign_extend to zero_extend:\n");
500+
print_rtl_single (dump_file, SET_SRC (set));
501+
}
502+
503+
if (!dbg_cnt (::ext_dce))
504+
{
505+
if (dump_file)
506+
fprintf (dump_file, "Rejected due to debug counter.\n");
507+
return;
508+
}
509+
510+
rtx new_pattern = gen_rtx_ZERO_EXTEND (GET_MODE (src), inner);
511+
int ok = validate_change (insn, &SET_SRC (set), new_pattern, false);
512+
513+
rtx x = SET_DEST (set);
514+
while (SUBREG_P (x) || GET_CODE (x) == ZERO_EXTRACT)
515+
x = XEXP (x, 0);
516+
517+
gcc_assert (REG_P (x));
518+
if (ok)
519+
{
520+
bitmap_set_bit (changed_pseudos, REGNO (x));
521+
remove_reg_equal_equiv_notes (insn, false);
522+
}
523+
524+
if (dump_file)
525+
{
526+
if (ok)
527+
fprintf (dump_file, "Successfully transformed to:\n");
528+
else
529+
fprintf (dump_file, "Failed transformation to:\n");
530+
print_rtl_single (dump_file, new_pattern);
531+
fprintf (dump_file, "\n");
532+
}
533+
return;
534+
}
535+
490536
/* Avoid (subreg (mem)) and other constructs which may be valid RTL, but
491537
not useful for this optimization. */
492538
if (!(REG_P (inner) || (SUBREG_P (inner) && REG_P (SUBREG_REG (inner)))))
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/* Verify that ext-dce narrows sign-extending loads to zero-extending loads
2+
when the upper bits are dead. */
3+
/* { dg-do compile } */
4+
/* { dg-options "-O2" } */
5+
/* { dg-final { check-function-bodies "**" "" } } */
6+
7+
/*
8+
** test_half:
9+
** ...
10+
** ldrh .*
11+
** ...
12+
*/
13+
/* Positive: halfword load-modify-store — sign bits are dead. */
14+
void
15+
test_half (signed short *p)
16+
{
17+
*p = (*p & 0xff00) | (0x00ff & (*p >> 8));
18+
}
19+
20+
/*
21+
** test_byte:
22+
** ...
23+
** ldrb .*
24+
** ...
25+
*/
26+
/* Positive: byte load-modify-store — sign bits are dead. */
27+
void
28+
test_byte (signed char *p)
29+
{
30+
*p = (*p & 0xf0) | (0x0f & (*p >> 4));
31+
}
32+
33+
/*
34+
** test_half_sign_needed:
35+
** ...
36+
** ldrsb .*
37+
** ...
38+
*/
39+
/* Negative: arithmetic right shift needs the sign extension. */
40+
int
41+
test_half_sign_needed (signed short *p)
42+
{
43+
return *p >> 8;
44+
}
45+
46+
/*
47+
** test_half_compare:
48+
** ...
49+
** ldrsh .*
50+
** ...
51+
*/
52+
/* Negative: sign-dependent comparison. */
53+
int
54+
test_half_compare (signed short *p)
55+
{
56+
return *p < 0;
57+
}
58+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* Verify ext-dce for word loads on RV64: lw sign-extends to 64 bits,
2+
so when the upper 32 bits are dead lw should be narrowed to lwu. */
3+
/* { dg-do compile } */
4+
/* { dg-require-effective-target rv64 } */
5+
/* { dg-options "-march=rv64gc -mabi=lp64d -O2" } */
6+
/* { dg-final { check-function-bodies "**" "" } } */
7+
8+
/*
9+
** test_word:
10+
** ...
11+
** lwu .*
12+
** ...
13+
*/
14+
/* Positive: word load-modify-store — upper 32 bits are dead. */
15+
void
16+
test_word (signed int *p)
17+
{
18+
*p = (*p & 0xffff0000) | (0x0000ffff & ((unsigned int)*p >> 16));
19+
}
20+
21+
/*
22+
** test_word_sign_needed:
23+
** ...
24+
** lw .*
25+
** ...
26+
*/
27+
/* Negative: return value is long — sign extension is needed. */
28+
long
29+
test_word_sign_needed (signed int *p)
30+
{
31+
return *p;
32+
}
33+
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/* Verify that ext-dce narrows sign-extending loads to zero-extending loads
2+
when the upper bits are dead. */
3+
/* { dg-do compile } */
4+
/* { dg-options "-O2" } */
5+
/* { dg-final { check-function-bodies "**" "" } } */
6+
7+
/*
8+
** test_half:
9+
** ...
10+
** lhu .*
11+
** ...
12+
*/
13+
/* Positive: halfword load-modify-store — sign bits are dead. */
14+
void
15+
test_half (signed short *p)
16+
{
17+
*p = (*p & 0xff00) | (0x00ff & (*p >> 8));
18+
}
19+
20+
/*
21+
** test_byte:
22+
** ...
23+
** lbu .*
24+
** ...
25+
*/
26+
/* Positive: byte load-modify-store — sign bits are dead. */
27+
void
28+
test_byte (signed char *p)
29+
{
30+
*p = (*p & 0xf0) | (0x0f & (*p >> 4));
31+
}
32+
33+
/*
34+
** test_half_sign_needed:
35+
** ...
36+
** lh .*
37+
** ...
38+
*/
39+
/* Negative: arithmetic right shift needs the sign extension. */
40+
int
41+
test_half_sign_needed (signed short *p)
42+
{
43+
return *p >> 8;
44+
}
45+
46+
/*
47+
** test_half_compare:
48+
** ...
49+
** lh .*
50+
** ...
51+
*/
52+
/* Negative: sign-dependent comparison. */
53+
int
54+
test_half_compare (signed short *p)
55+
{
56+
return *p < 0;
57+
}
58+

0 commit comments

Comments
 (0)