Skip to content

Commit

Permalink
arcv: implement bit-extract fusion
Browse files Browse the repository at this point in the history
The bitfield zero_extract operation is normally expanded into an srai
followed by an andi.  (With the ZBS extension enabled, the special case
of 1-bit zero-extract is implemented with the bexti insn.)  However,
since the RHX core can execute a shift-left and a shift-right of the
same register in 1 cycle, we would prefer to emit those two instructions
instead, and schedule them together so that macro fusion can take place.

The required steps to achieve this are:

(1) Create an insn_and_split that handles the zero_extract RTX;
(2) Tell the combiner to use that split by lowering the cost of the
zero_extract RTX when the target is the RHX core;
(3) Designate the resulting slli + srli pair as fusable by the scheduler.

Attached is a small testcase demonstrating the split, and that the bexti
insn still takes priority over the shift pair.

Signed-off-by: Artemiy Volkov <artemiy@synopsys.com>
  • Loading branch information
artemiy-volkov committed Aug 20, 2024
1 parent 654efd4 commit 2677e8b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 1 deletion.
10 changes: 9 additions & 1 deletion gcc/config/riscv/riscv.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3454,7 +3454,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
}
gcc_fallthrough ();
case SIGN_EXTRACT:
if (TARGET_XTHEADBB && outer_code == SET
if ((riscv_is_micro_arch (rhx) || TARGET_XTHEADBB)
&& outer_code == SET
&& CONST_INT_P (XEXP (x, 1))
&& CONST_INT_P (XEXP (x, 2)))
{
Expand Down Expand Up @@ -8860,6 +8861,13 @@ arcv_macro_fusion_pair_p (rtx_insn *prev, rtx_insn *curr)
|| REGNO (SET_DEST (prev_set)) == REGNO (XEXP (SET_SRC (curr_set), 1))))
return true;

/* Fuse logical shift left with logical shift right (bit-extract pattern). */
if (GET_CODE (SET_SRC (prev_set)) == ASHIFT
&& GET_CODE (SET_SRC (curr_set)) == LSHIFTRT
&& REGNO (SET_DEST (prev_set)) == REGNO (SET_DEST (curr_set))
&& REGNO (SET_DEST (prev_set)) == REGNO (XEXP (SET_SRC (curr_set), 0)))
return true;

return false;
}

Expand Down
20 changes: 20 additions & 0 deletions gcc/config/riscv/riscv.md
Original file line number Diff line number Diff line change
Expand Up @@ -3786,6 +3786,26 @@
[(set_attr "type" "imul")]
)

(define_insn_and_split "*zero_extract_split"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand 2 "const_int_operand")
(match_operand 3 "const_int_operand")))]
"riscv_is_micro_arch (rhx) && !TARGET_64BIT
&& (INTVAL (operands[2]) > 1 || !TARGET_ZBS)"
"#"
"&& 1"
[(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 3)))]
"{
int amount = INTVAL (operands[2]);
int end = INTVAL (operands[3]) + amount;
operands[2] = GEN_INT (BITS_PER_WORD - end);
operands[3] = GEN_INT (BITS_PER_WORD - amount);
}"
[(set_attr "type" "bitmanip")]
)

;; String compare with length insn.
;; Argument 0 is the target (result)
;; Argument 1 is the source1
Expand Down
14 changes: 14 additions & 0 deletions gcc/testsuite/gcc.target/riscv/arcv-fusion-xbfu.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* { dg-do compile } */
/* { dg-require-effective-target rv32 } */
/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-Oz" "-Os" } } */
/* { dg-options "-mtune=rhx -march=rv32im_zbs -mabi=ilp32" } */

#define bit_extract(x,start,amt) (((x)>>(start)) & (~(0xffffffff << (amt))))

int
f (int x)
{
return bit_extract(x,10,14) + bit_extract(x,1,1);
}

/* { dg-final { scan-assembler {\sslli\s([ast][0-9]+),a0,8\n\ssrli\s\1,\1,18\n\sbexti\sa0,a0,1\n\sadd\sa0,\1,a0\n} } } */

0 comments on commit 2677e8b

Please sign in to comment.