diff mbox series

RISC-V: Use bseti to cover more immediates than with ori alone

Message ID 20221110213445.3592438-1-philipp.tomsich@vrull.eu
State New
Headers show
Series RISC-V: Use bseti to cover more immediates than with ori alone | expand

Commit Message

Philipp Tomsich Nov. 10, 2022, 9:34 p.m. UTC
Sequences of the form "a | C" with C being the positive half of a
signed immediate's range with one extra bit set in addtion are mapped
to ori and one binvi to avoid using a temporary (and a multi-insn
sequence to load C into that temporary).

gcc/ChangeLog:

	* config/riscv/bitmanip.md (*bseti<mode>_extrabit): New pattern

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zbs-bseti.c: New test.

Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---
- Depends on a predicate posted in "RISC-V: Optimize branches testing
  a bit-range or a shifted immediate".  Depending on the order of
  applying these, I'll take care to pull that part out of the other
  patch if needed.

 gcc/config/riscv/bitmanip.md               | 19 +++++++++++++++
 gcc/testsuite/gcc.target/riscv/zbs-bseti.c | 27 ++++++++++++++++++++++
 2 files changed, 46 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-bseti.c

Comments

Jeff Law Nov. 16, 2022, 3:43 a.m. UTC | #1
On 11/10/22 14:34, Philipp Tomsich wrote:
> Sequences of the form "a | C" with C being the positive half of a
> signed immediate's range with one extra bit set in addtion are mapped
> to ori and one binvi to avoid using a temporary (and a multi-insn
> sequence to load C into that temporary).
>
> gcc/ChangeLog:
>
> 	* config/riscv/bitmanip.md (*bseti<mode>_extrabit): New pattern
>
> gcc/testsuite/ChangeLog:
>
> 	* gcc.target/riscv/zbs-bseti.c: New test.
>
> Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
> ---
> - Depends on a predicate posted in "RISC-V: Optimize branches testing
>    a bit-range or a shifted immediate".  Depending on the order of
>    applying these, I'll take care to pull that part out of the other
>    patch if needed.
>
>   gcc/config/riscv/bitmanip.md               | 19 +++++++++++++++
>   gcc/testsuite/gcc.target/riscv/zbs-bseti.c | 27 ++++++++++++++++++++++
>   2 files changed, 46 insertions(+)
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-bseti.c
>
> diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
> index 06126ac4819..436ff4ba958 100644
> --- a/gcc/config/riscv/bitmanip.md
> +++ b/gcc/config/riscv/bitmani
> @@ -512,6 +512,25 @@
>     "bseti\t%0,%1,%S2"
>     [(set_attr "type" "bitmanip")])
>   
> +; Catch those cases where we can use a bseti + ori or bseti + bseti
> +; instead of a lui + addi + or sequence.
> +(define_insn_and_split "*bseti<mode>_extrabit"
> +  [(set (match_operand:X 0 "register_operand" "=r")
> +	(ior:X (match_operand:X 1 "register_operand" "r")
> +	       (match_operand:X 2 "uimm_extra_bit_operand" "i")))]
> +  "TARGET_ZBS"
> +  "#"
> +  "&& reload_completed"
> +  [(set (match_dup 0) (ior:X (match_dup 1) (match_dup 3)))
> +   (set (match_dup 0) (ior:X (match_dup 0) (match_dup 4)))]
> +{
> +	unsigned HOST_WIDE_INT bits = UINTVAL (operands[2]);
> +	unsigned HOST_WIDE_INT topbit = HOST_WIDE_INT_1U << floor_log2 (bits);
> +
> +	operands[3] = GEN_INT (bits &~ topbit);
> +	operands[4] = GEN_INT (topbit);
> +})

I briefly thought you might need an earlyclobber for the output, but you 
consume the input register in the first generated insn, so you should be OK.


OK.

jeff
diff mbox series

Patch

diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index 06126ac4819..436ff4ba958 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -512,6 +512,25 @@ 
   "bseti\t%0,%1,%S2"
   [(set_attr "type" "bitmanip")])
 
+; Catch those cases where we can use a bseti + ori or bseti + bseti
+; instead of a lui + addi + or sequence.
+(define_insn_and_split "*bseti<mode>_extrabit"
+  [(set (match_operand:X 0 "register_operand" "=r")
+	(ior:X (match_operand:X 1 "register_operand" "r")
+	       (match_operand:X 2 "uimm_extra_bit_operand" "i")))]
+  "TARGET_ZBS"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0) (ior:X (match_dup 1) (match_dup 3)))
+   (set (match_dup 0) (ior:X (match_dup 0) (match_dup 4)))]
+{
+	unsigned HOST_WIDE_INT bits = UINTVAL (operands[2]);
+	unsigned HOST_WIDE_INT topbit = HOST_WIDE_INT_1U << floor_log2 (bits);
+
+	operands[3] = GEN_INT (bits &~ topbit);
+	operands[4] = GEN_INT (topbit);
+})
+
 ;; As long as the SImode operand is not a partial subreg, we can use a
 ;; bseti without postprocessing, as the middle end is smart enough to
 ;; stay away from the signbit.
diff --git a/gcc/testsuite/gcc.target/riscv/zbs-bseti.c b/gcc/testsuite/gcc.target/riscv/zbs-bseti.c
new file mode 100644
index 00000000000..5738add6348
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zbs-bseti.c
@@ -0,0 +1,27 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+long long foo1 (long long a)
+{
+  return a | 0x1100;
+}
+
+long long foo2 (long long a)
+{
+  return a | 0x80000000000000ffull;
+}
+
+long long foo3 (long long a)
+{
+  return a | 0x8000000100000000ull;
+}
+
+long long foo4 (long long a)
+{
+  return a | 0xfff;
+}
+
+/* { dg-final { scan-assembler-times "bseti\t" 5 } } */
+/* { dg-final { scan-assembler-times "ori\t" 3 } } */
+