[PATCH] LoongArch: improve 64-bit bitwise AND operation
"Ben Shi" <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
It usually costs 4-5 instructions for 64-bit bitwise AND with a large immediate. For some immediates the operation can be simplified to two 'BSTRINS.D' instructions if the immediate satisfies: 1. its top bit is not zero. 2. has two sections of consecutive zero bits. gcc/ChangeLog: * config/loongarch/loongarch.md: Add a new RTL expression (define_insn_and_split "bstrins_bstrins_for_and_imm"). * config/loongarch/loongarch.cc: Add a helper function 'loongarch_use_bstrins_bstrins_for_and' for the above RTL expression. * config/loongarch/loongarch-protos.h: Add prototype of function 'loongarch_use_bstrins_bstrins_for_and'. * testsuite/gcc.target/loongarch/la64/and-large-immediate-opt-2.c: Add a new test. Signed-off-by: Ben Shi <[email protected]> --- gcc/config/loongarch/loongarch-protos.h | 1 + gcc/config/loongarch/loongarch.cc | 30 +++++++++++++++++++ gcc/config/loongarch/loongarch.md | 30 +++++++++++++++++++ .../la64/and-large-immediate-opt-2.c | 13 ++++++++ 4 files changed, 74 insertions(+) create mode 100644 gcc/testsuite/gcc.target/loongarch/la64/and-large-immediate-opt-2.c diff --git a/gcc/config/loongarch/loongarch-protos.h b/gcc/config/loongarch/loongarch-protos.h index e67addf36e3..93e78972a9a 100644 --- a/gcc/config/loongarch/loongarch-protos.h +++ b/gcc/config/loongarch/loongarch-protos.h @@ -162,6 +162,7 @@ extern bool loongarch_check_zero_div_p (void); extern bool loongarch_pre_reload_split (void); extern int loongarch_use_bstrins_for_ior_with_mask (machine_mode, rtx *); extern bool loongarch_use_bstrins_bstrpick_for_and (rtx, machine_mode); +extern bool loongarch_use_bstrins_bstrins_for_and (rtx, machine_mode); extern rtx loongarch_rewrite_mem_for_simple_ldst (rtx); union loongarch_gen_fn_ptrs diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index b0f7abc0483..986a6594322 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -4034,6 +4034,36 @@ loongarch_use_bstrins_bstrpick_for_and (rtx op, machine_mode mode) return false; } +/* Check if it is possible to optimize AND operation with an immediate: + a. immediate is loaded by more than 2 instruction + b. can use two 'bstrins.d' instructions. + This immediate must be satisfy: + a. its top bit is not zero + b. has two sections of consecutive zero bits. */ + +bool +loongarch_use_bstrins_bstrins_for_and (rtx op, machine_mode mode) +{ + if (loongarch_integer_cost (UINTVAL (op)) <= 2) + return false; + + /* It's meaningless if the OP is not splittable + and skip the cases already supported in AND operation. */ + if (!splittable_const_int_operand (op, mode) || and_operand (op, mode)) + return false; + + /* If the leading one bits are set to zero, the value should match + the pattern of 'bstrins_bstrpick_for_and_imm'. */ + int lead_one_bits = clz_hwi (~UINTVAL (op)); + unsigned HOST_WIDE_INT one = 1; + unsigned HOST_WIDE_INT lead_one_mask = (one + << (HOST_BITS_PER_WIDE_INT + - lead_one_bits)) + - 1; + unsigned HOST_WIDE_INT new_val = lead_one_mask & UINTVAL (op); + return loongarch_use_bstrins_bstrpick_for_and (GEN_INT (new_val), mode); +} + /* Return the cost of moving between two registers of mode MODE. */ static int diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md index 37ae5a2223e..5f9a11875c2 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -1783,6 +1783,36 @@ } [(set_attr "length" "8")]) +(define_insn_and_split "bstrins_bstrins_for_and_imm" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "const_int_operand" "i")))] + "TARGET_64BIT + && loongarch_use_bstrins_bstrins_for_and (operands[2], DImode)" + "#" + "&& true" + [(const_int 0)] +{ + unsigned HOST_WIDE_INT op2 = INTVAL (operands[2]); + int lead_one_bits = clz_hwi (~op2); + unsigned HOST_WIDE_INT zero = 0, one = 1; + unsigned HOST_WIDE_INT lead_one_mask = (~zero) + << (HOST_BITS_PER_WIDE_INT + - lead_one_bits); + unsigned HOST_WIDE_INT new_val = op2 & ~lead_one_mask; + int bit_num = clz_hwi (new_val); + unsigned HOST_WIDE_INT mask_hi = lead_one_mask + | ((one + << (HOST_BITS_PER_WIDE_INT - bit_num)) + - 1); + unsigned HOST_WIDE_INT mask_lo = (~zero) + << (HOST_BITS_PER_WIDE_INT - bit_num); + emit_move_insn (operands[0], operands[1]); + emit_insn (gen_anddi3 (operands[0], operands[0], GEN_INT (mask_hi))); + emit_insn (gen_anddi3 (operands[0], operands[0], + GEN_INT (new_val | mask_lo))); +}) + (define_insn "*iorhi3" [(set (match_operand:HI 0 "register_operand" "=r,r") (ior:HI (match_operand:HI 1 "register_operand" "%r,r") diff --git a/gcc/testsuite/gcc.target/loongarch/la64/and-large-immediate-opt-2.c b/gcc/testsuite/gcc.target/loongarch/la64/and-large-immediate-opt-2.c new file mode 100644 index 00000000000..c2121b374eb --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/la64/and-large-immediate-opt-2.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target { loongarch64*-*-* } } } */ +/* { dg-options "-O3" } */ +/* { dg-final { scan-assembler-not "\tlu12i.w" } } */ +/* { dg-final { scan-assembler-not "\tori" } } */ +/* { dg-final { scan-assembler-not "\tlu52i.d" } } */ +/* { dg-final { scan-assembler-not "\tand" } } */ +/* { dg-final { scan-assembler "\tbstrins.d" } } */ + +long +test (long a) +{ + return a & 0xff0fffffffff0fffLL; +}</[email protected]>