For the following immediate load operation in 
gcc/testsuite/gcc.target/loongarch/imm-load1.c:

        long long r = 0x0101010101010101;

Before this patch:

        lu12i.w     $r15,16842752>>12
        ori         $r15,$r15,257
        lu32i.d     $r15,0x1010100000000>>32
        lu52i.d     $r15,$r15,0x100000000000000>>52

After this patch:

        lu12i.w     $r15,16842752>>12
        ori         $r15,$r15,257
        bstrins.d   $r15,$r15,63,32

gcc/ChangeLog:

        * config/loongarch/loongarch.cc (enum loongarch_load_imm_method): Add 
new method.
        (loongarch_build_integer): Add relevant implementations for new method.
        (loongarch_move_integer): Ditto.

gcc/testsuite/ChangeLog:

        * gcc.target/loongarch/imm-load1.c: Change old check.
---
 gcc/config/loongarch/loongarch.cc             | 22 ++++++++++++++++++-
 .../gcc.target/loongarch/imm-load1.c          |  3 ++-
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/gcc/config/loongarch/loongarch.cc 
b/gcc/config/loongarch/loongarch.cc
index d05743bec87..58c00344d09 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -142,12 +142,16 @@ struct loongarch_address_info
 
    METHOD_LU52I:
      Load 52-63 bit of the immediate number.
+
+   METHOD_MIRROR:
+     Copy 0-31 bit of the immediate number to 32-63bit.
 */
 enum loongarch_load_imm_method
 {
   METHOD_NORMAL,
   METHOD_LU32I,
-  METHOD_LU52I
+  METHOD_LU52I,
+  METHOD_MIRROR
 };
 
 struct loongarch_integer_op
@@ -1556,11 +1560,23 @@ loongarch_build_integer (struct loongarch_integer_op 
*codes,
 
       int sign31 = (value & (HOST_WIDE_INT_1U << 31)) >> 31;
       int sign51 = (value & (HOST_WIDE_INT_1U << 51)) >> 51;
+
+      unsigned HOST_WIDE_INT hival = value >> 32;
+      unsigned HOST_WIDE_INT loval = value << 32 >> 32;
+
       /* Determine whether the upper 32 bits are sign-extended from the lower
         32 bits. If it is, the instructions to load the high order can be
         ommitted.  */
       if (lu32i[sign31] && lu52i[sign31])
        return cost;
+      /* If the lower 32 bits are the same as the upper 32 bits, just copy
+        the lower 32 bits to the upper 32 bits.  */
+      else if (loval == hival)
+       {
+         codes[cost].method = METHOD_MIRROR;
+         codes[cost].curr_value = value;
+         return cost + 1;
+       }
       /* Determine whether bits 32-51 are sign-extended from the lower 32
         bits. If so, directly load 52-63 bits.  */
       else if (lu32i[sign31])
@@ -3230,6 +3246,10 @@ loongarch_move_integer (rtx temp, rtx dest, unsigned 
HOST_WIDE_INT value)
                           gen_rtx_AND (DImode, x, GEN_INT (0xfffffffffffff)),
                           GEN_INT (codes[i].value));
          break;
+       case METHOD_MIRROR:
+         gcc_assert (mode == DImode);
+         emit_insn (gen_insvdi (x, GEN_INT (32), GEN_INT (32), x));
+         break;
        default:
          gcc_unreachable ();
        }
diff --git a/gcc/testsuite/gcc.target/loongarch/imm-load1.c 
b/gcc/testsuite/gcc.target/loongarch/imm-load1.c
index 2ff02971239..f64cc2956a3 100644
--- a/gcc/testsuite/gcc.target/loongarch/imm-load1.c
+++ b/gcc/testsuite/gcc.target/loongarch/imm-load1.c
@@ -1,6 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-mabi=lp64d -O2" } */
-/* { dg-final { scan-assembler "test:.*lu52i\.d.*\n\taddi\.w.*\n\.L2:" } } */
+/* { dg-final { scan-assembler-not "test:.*lu52i\.d.*\n\taddi\.w.*\n\.L2:" } } 
*/
+/* { dg-final { scan-assembler "test:.*lu12i\.w.*\n\tbstrins\.d.*\n\.L2:" } } 
*/
 
 
 extern long long b[10];
-- 
2.20.1

Reply via email to