https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124008
Bug ID: 124008
Summary: Improve RTL reassociation to eliminate terms in
expressions
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: law at gcc dot gnu.org
Target Milestone: ---
In _ZN11xalanc_1_1019XalanDOMStringCache7releaseERNS_14XalanDOMStringE in xalan
when compiled with -O2 -march=rv64gcbv_zicond on riscv, we have this sequence
generated for an idiom created by one of the RTL passes:
addi a5,a5,-8
srli a5,a5,3
addi a5,a5,1
Which is ((a - 8) >> 3) + 1
We can left shift the + 1 by 3 positions and bring it into the innermost
expression resulting in:
((a - 8 + 8) >> 3)
Which naturally simplifies into (a >> 3).
Something like this in simplify-rtx. Note this probably doesn't deal with
overflows properly, nor does it deal with large modes where we can't represent
the shifted constants in a HOST_WIDE_INT, etc. But it does show the basic
structure for how we might solve this problem:
diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index 516d626e2f5..0727bd8f484 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -3156,6 +3156,27 @@ simplify_context::simplify_binary_operation_1 (rtx_code
code,
simplify_gen_binary (XOR, mode, op1,
XEXP (op0, 1)));
+ /* (plus (lshiftrt (plus X C1) C2) C3) can be transformed into
+ (lshiftrt (plus X C1') C2) where C1' is C1 - (C3 << C2). C1
+ may be zero allowing further simplification. */
+ if (is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_CODE (op0) == LSHIFTRT
+ && CONST_INT_P (XEXP (op0, 1))
+ && GET_CODE (XEXP (op0, 0)) == PLUS
+ && CONST_INT_P (XEXP (XEXP (op0, 0), 1))
+ && CONST_INT_P (op1))
+ {
+ rtx plus_expr = XEXP (op0, 0);
+ HOST_WIDE_INT c1 = INTVAL (XEXP (plus_expr, 1));
+ HOST_WIDE_INT c2 = INTVAL (XEXP (op0, 1));
+ HOST_WIDE_INT c3 = INTVAL (op1);
+ rtx x = simplify_gen_binary (PLUS, mode,
+ XEXP (plus_expr, 0),
+ GEN_INT (c1 + (c3 << c2)));
+ x = simplify_gen_binary (LSHIFTRT, mode, x, XEXP (op0, 1));
+ return x;
+ }
+
/* Canonicalize (plus (mult (neg B) C) A) to (minus A (mult B C)). */
if (!HONOR_SIGN_DEPENDENT_ROUNDING (mode)
&& GET_CODE (op0) == MULT
That saves two dependent instructions.