In some cases, the pre pass will separate the shift and add  of
shift+add+ld/st ins into different blocks, resulting in combine ldx/stx
instead of alsl, but for consecutive reg+reg memory access instructions,
this may cause read port conflicts and reduce efficiency.

Try to directly generate alsl, processing the following RTL into alsl:
(plus:DI (mult:DI (reg/v:DI 81 [ index ])
        (const_int 4 [0x4]))
    (reg/f:DI 84))

todo:
(plus:DI (ashift:DI (reg/v:DI 81 [ index ])
        (const_int 2 [0x4]))
    (reg/f:DI 84))

ADD_OPTIONS: -mcombine-addr-alsl

gcc/ChangeLog:

        * config/loongarch/genopts/loongarch.opt.in: Add new option.
        * config/loongarch/loongarch.cc: Add specific case function.
        * config/loongarch/loongarch.opt: Add new option.

gcc/testsuite/ChangeLog:

        * gcc.target/loongarch/alsl_addr.c: New test.
---
 gcc/config/loongarch/genopts/loongarch.opt.in |  4 ++
 gcc/config/loongarch/loongarch.cc             | 37 +++++++++++++++++++
 gcc/config/loongarch/loongarch.opt            |  4 ++
 .../gcc.target/loongarch/alsl_addr.c          | 34 +++++++++++++++++
 4 files changed, 79 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/alsl_addr.c

diff --git a/gcc/config/loongarch/genopts/loongarch.opt.in 
b/gcc/config/loongarch/genopts/loongarch.opt.in
index f0c089a928e..b8e4ed6cebe 100644
--- a/gcc/config/loongarch/genopts/loongarch.opt.in
+++ b/gcc/config/loongarch/genopts/loongarch.opt.in
@@ -313,3 +313,7 @@ HOST_WIDE_INT la_isa_evolution = 0
 mannotate-tablejump
 Target Mask(ANNOTATE_TABLEJUMP) Save
 Annotate table jump instruction (jr {reg}) to correlate it with the jump table.
+
+mcombine-addr-alsl
+Target Var(flag_la_combine_addr_alsl) Optimization Init(0)
+Enable to simplify instructions of base address and index to alsl.
diff --git a/gcc/config/loongarch/loongarch.cc 
b/gcc/config/loongarch/loongarch.cc
index fcca0ec8252..c10f0df9472 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -3419,6 +3419,22 @@ mem_shadd_or_shadd_rtx_p (rtx x)
                  && IN_RANGE (exact_log2 (INTVAL (XEXP (x, 1))), 1, 3))));
 }
 
+/* Helper loongarch_legitimize_address.  Given X, return true if it
+   is a left shift by 1, 2, 3 or 4 positions or a multiply by 2, 4, 8 or 16.
+
+   This respectively represent canonical shift-add rtxs or scaled
+   memory addresses.  */
+static bool
+mem_shadd_or_shadd_rtx_p_1 (rtx x)
+{
+  return ((GET_CODE (x) == ASHIFT
+          || GET_CODE (x) == MULT)
+         && CONST_INT_P (XEXP (x, 1))
+         && ((GET_CODE (x) == ASHIFT && IN_RANGE (INTVAL (XEXP (x, 1)), 1, 4))
+             || (GET_CODE (x) == MULT
+                 && IN_RANGE (exact_log2 (INTVAL (XEXP (x, 1))), 1, 4))));
+}
+
 /* This function is used to implement LEGITIMIZE_ADDRESS.  If X can
    be legitimized in a way that the generic machinery might not expect,
    return a new address, otherwise return NULL.  MODE is the mode of
@@ -3475,6 +3491,27 @@ loongarch_legitimize_address (rtx x, rtx oldx 
ATTRIBUTE_UNUSED,
       return loongarch_force_address (addr, mode);
     }
 
+  if (flag_la_combine_addr_alsl
+      && oldx == x
+      && GET_CODE (x) == PLUS && mem_shadd_or_shadd_rtx_p_1 (XEXP (x, 0))
+      && REG_P (XEXP (x, 1)))
+    {
+      rtx index = XEXP (x, 0);
+      rtx org_base = XEXP (x, 1);
+
+      int shift_val = INTVAL (XEXP (index, 1));
+      if (GET_CODE (index) == MULT)
+       shift_val = exact_log2 (shift_val);
+
+      rtx reg1 = gen_reg_rtx (Pmode);
+      loongarch_emit_binary (PLUS, reg1,
+                            gen_rtx_ASHIFT (Pmode, XEXP (index, 0),
+                                            GEN_INT (shift_val)),
+                            org_base);
+
+      return reg1;
+    }
+
   return x;
 }
 
diff --git a/gcc/config/loongarch/loongarch.opt 
b/gcc/config/loongarch/loongarch.opt
index 628eabe8d59..1bcfa7f3fd1 100644
--- a/gcc/config/loongarch/loongarch.opt
+++ b/gcc/config/loongarch/loongarch.opt
@@ -345,3 +345,7 @@ Support sc.q instruction.
 mld-seq-sa
 Target Mask(ISA_LD_SEQ_SA) Var(la_isa_evolution)
 Do not need load-load barriers (dbar 0x700).
+
+mcombine-addr-alsl
+Target Var(flag_la_combine_addr_alsl) Optimization Init(0)
+Enable to simplify instructions of base address and index to alsl.
diff --git a/gcc/testsuite/gcc.target/loongarch/alsl_addr.c 
b/gcc/testsuite/gcc.target/loongarch/alsl_addr.c
new file mode 100644
index 00000000000..9eca0c48964
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/alsl_addr.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcombine-addr-alsl" } */
+
+extern int arr_i[];
+extern float arr_f[];
+
+void
+foo_i (int index, int ra, int rb)
+{
+  int org = arr_i[index];
+  arr_i[index] = ra;
+
+  if (ra > rb)
+    arr_i[ra] = org;
+  else
+    arr_i[rb] = org;
+}
+
+void
+foo_f (int index, int ra, int rb, float rc)
+{
+  float org = arr_f[index];
+  arr_f[index] = rc;
+
+  if (ra > rb)
+    arr_f[ra] = org;
+  else
+    arr_f[rb] = org;
+}
+
+/* { dg-final { scan-assembler-not "ldx\.\[dw\]" } } */
+/* { dg-final { scan-assembler-not "fldx\.\[sw\]" } } */
+/* { dg-final { scan-assembler-not "stx\.\[dw\]" } } */
+/* { dg-final { scan-assembler-not "fstx\.\[sw\]" } } */
-- 
2.20.1

Reply via email to