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 && hival)
+ {
+ int hb = HOST_BITS_PER_WIDE_INT - clz_hwi (~value);
+ int lb = ctz_hwi (~hival) + 32;
+ gcc_assert (lb >= 0 && lb < 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 < HOST_BITS_PER_WIDE_INT && hb - lb == popcount_hwi
(~hival))
+ {
+ codes[cost].method = METHOD_BSTRINS;
+ codes[cost].value = (hb << 16) | lb;
+ codes[cost].curr_value = value;
+ return cost + 1;
+ }
+ }
codes[cost].method = METHOD_LU32I;
codes[cost].value = (value & 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 & 0xffff;
+ int hb = codes[i].value >> 16;
+ x = gen_rtx_AND (DImode, x, GEN_INT (~((one << hb) - (one
<< 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:.*>>.*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]>