[PATCH] LoongArch: improve building large integers

"Ben Shi" <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
An ordinary 64-bit integer usually costs 4 instructions to be built.

Some integers can be simplified to 3 instructions, that the upper
32-bit can be built with a single 'BSTRINS.D' instead of a pair of
'LU32I.D' and 'LU52I.D'. If these integers are in the pattern:

1. Bit-31 is one.
2. Upper 32-bit is in the pattern of '11..1100..0011..11'.

gcc/ChangeLog:

        * config/loongarch/loongarch.cc: Add a new special case in
          'loongarch_build_integer' and a new method 'METHOD_BSTRINS'.

        * testsuite/gcc.target/loongarch/la64/imm-load-2.c: New test.

Signed-off-by: Ben Shi <[email protected]>
---
 gcc/config/loongarch/loongarch.cc             | 30 ++++++++++++++++++-
 .../gcc.target/loongarch/la64/imm-load-2.c    | 11 +++++++
 2 files changed, 40 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/la64/imm-load-2.c

diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index 0831da018ff..57e4dd09849 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -152,7 +152,8 @@ enum loongarch_load_imm_method
   METHOD_NORMAL,
   METHOD_LU32I,
   METHOD_LU52I,
-  METHOD_MIRROR
+  METHOD_MIRROR,
+  METHOD_BSTRINS,
 };

 struct loongarch_integer_op
@@ -1640,6 +1641,24 @@ loongarch_build_integer (struct loongarch_integer_op *codes,
          codes[cost].curr_value = value;
          return cost + 1;
        }
+      /* If bit-31 is one, while the upper 32-bit is in the form of
+        '11..1100..0011...11', use 'BSTRINS.D' instead of a pair of
+        'LU32I.D' and 'LU52I.D'.  */
+      else if (sign31 &amp;&amp; hival)
+       {
+         int hb = HOST_BITS_PER_WIDE_INT - clz_hwi (~value);
+         int lb = ctz_hwi (~hival) + 32;
+         gcc_assert (lb &gt;= 0 &amp;&amp; lb &lt; hb);
+         /* Skip if leading bits are zeros, since a single 'LU32I.D' or
+            'LU52I.D' can be emitted for the upper 32-bit.  */
+         if (hb &lt; HOST_BITS_PER_WIDE_INT &amp;&amp; hb - lb == popcount_hwi (~hival))
+           {
+             codes[cost].method = METHOD_BSTRINS;
+             codes[cost].value = (hb &lt;&lt; 16) | lb;
+             codes[cost].curr_value = value;
+             return cost + 1;
+           }
+       }

       codes[cost].method = METHOD_LU32I;
       codes[cost].value = (value &amp; LU32I_B) | (sign51 ? LU52I_B : 0);
@@ -3663,6 +3682,15 @@ loongarch_move_integer (rtx temp, rtx dest, unsigned HOST_WIDE_INT value)
          gcc_assert (mode == DImode);
          emit_insn (gen_insvdi (x, GEN_INT (32), GEN_INT (32), x));
          break;
+       case METHOD_BSTRINS:
+         {
+           gcc_assert (mode == DImode);
+           unsigned HOST_WIDE_INT one = 1;
+           int lb = codes[i].value &amp; 0xffff;
+           int hb = codes[i].value &gt;&gt; 16;
+           x = gen_rtx_AND (DImode, x, GEN_INT (~((one &lt;&lt; hb) - (one &lt;&lt; lb))));
+           break;
+         }
        default:
          gcc_unreachable ();
        }
diff --git a/gcc/testsuite/gcc.target/loongarch/la64/imm-load-2.c b/gcc/testsuite/gcc.target/loongarch/la64/imm-load-2.c
new file mode 100644
index 00000000000..356eb43f229
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/la64/imm-load-2.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O2 -fdump-rtl-split1" } */
+/* { dg-final { scan-assembler-not "test:.*&gt;&gt;.*test" } } */
+
+long int
+test (void)
+{
+  return 0xfe0003ffaaaaccccl;
+}
+/* { dg-final { scan-rtl-dump-times "scanning new insn with uid" 3 "split1" } } */
+
--
2.39.3</[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.