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]>

Reply via email to