Skip to content

Commit

Permalink
RISC-V: Implement instruction patterns for ZBS extension.
Browse files Browse the repository at this point in the history
2021-10-25  Jim Wilson  <jimw@sifive.com>
	    Kito Cheng  <kito.cheng@sifive.com>

gcc/ChangeLog:

	* config/riscv/bitmanip.md (shiftm1): New.
	(*bset<mode>): Ditto.
	(*bset<mode>_mask): Ditto.
	(*bset<mode>_1): Ditto.
	(*bset<mode>_1_mask): Ditto.
	(*bseti<mode>): Ditto.
	(*bclr<mode>): Ditto.
	(*bclri<mode>): Ditto.
	(*binv<mode>): Ditto.
	(*binvi<mode>): Ditto.
	(*bext<mode>): Ditto.
	(*bexti): Ditto.
	* config/riscv/predicates.md (splittable_const_int_operand):
	Handle bseti.
	(single_bit_mask_operand): New.
	(not_single_bit_mask_operand): Ditto.
	(const31_operand): Ditto.
	(const63_operand): Ditto.
	* config/riscv/riscv.c (riscv_build_integer_1): Handle bseti.
	(riscv_output_move): Ditto.
	(riscv_print_operand): Handle new operand type: T and S.
	* config/riscv/riscv.h (SINGLE_BIT_MASK_OPERAND): New.

2021-10-25  Jia-Wei Chen  <jiawei@iscas.ac.cn>
	    Shi-Hua Liao  <shihua@iscas.ac.cn>

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zba-slliuw.c: Apply zbs to this testcase.
	* gcc.target/riscv/zbs-bclr.c: New.
	* gcc.target/riscv/zbs-bext.c: Ditto.
	* gcc.target/riscv/zbs-binv.c: Ditto.
	* gcc.target/riscv/zbs-bset.c: Ditto.

Co-authored-by: Kito Cheng <kito.cheng@sifive.com>
Co-authored-by: Jia-Wei Chen <jiawei@iscas.ac.cn>
Co-authored-by: Shi-Hua Liao <shihua@iscas.ac.cn>
  • Loading branch information
4 people committed Oct 25, 2021
1 parent 26d2818 commit 4e1e0d7
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 4 deletions.
102 changes: 102 additions & 0 deletions gcc/config/riscv/bitmanip.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
(ctz "ctz")
(popcount "cpop")])

(define_mode_attr shiftm1 [(SI "const31_operand") (DI "const63_operand")])

;; ZBA extension.

Expand Down Expand Up @@ -238,3 +239,104 @@
"TARGET_ZBB"
"<bitmanip_insn>\t%0,%1,%2"
[(set_attr "type" "bitmanip")])

;; ZBS extension.

(define_insn "*bset<mode>"
[(set (match_operand:X 0 "register_operand" "=r")
(ior:X (ashift:X (const_int 1)
(match_operand:QI 2 "register_operand" "r"))
(match_operand:X 1 "register_operand" "r")))]
"TARGET_ZBS"
"bset\t%0,%1,%2"
[(set_attr "type" "bitmanip")])

(define_insn "*bset<mode>_mask"
[(set (match_operand:X 0 "register_operand" "=r")
(ior:X (ashift:X (const_int 1)
(subreg:QI
(and:X (match_operand:X 2 "register_operand" "r")
(match_operand 3 "<X:shiftm1>" "i")) 0))
(match_operand:X 1 "register_operand" "r")))]
"TARGET_ZBS"
"bset\t%0,%1,%2"
[(set_attr "type" "bitmanip")])

(define_insn "*bset<mode>_1"
[(set (match_operand:X 0 "register_operand" "=r")
(ashift:X (const_int 1)
(match_operand:QI 1 "register_operand" "r")))]
"TARGET_ZBS"
"bset\t%0,x0,%1"
[(set_attr "type" "bitmanip")])

(define_insn "*bset<mode>_1_mask"
[(set (match_operand:X 0 "register_operand" "=r")
(ashift:X (const_int 1)
(subreg:QI
(and:X (match_operand:X 1 "register_operand" "r")
(match_operand 2 "<X:shiftm1>" "i")) 0)))]
"TARGET_ZBS"
"bset\t%0,x0,%1"
[(set_attr "type" "bitmanip")])

(define_insn "*bseti<mode>"
[(set (match_operand:X 0 "register_operand" "=r")
(ior:X (match_operand:X 1 "register_operand" "r")
(match_operand 2 "single_bit_mask_operand" "i")))]
"TARGET_ZBS"
"bseti\t%0,%1,%S2"
[(set_attr "type" "bitmanip")])

(define_insn "*bclr<mode>"
[(set (match_operand:X 0 "register_operand" "=r")
(and:X (rotate:X (const_int -2)
(match_operand:QI 2 "register_operand" "r"))
(match_operand:X 1 "register_operand" "r")))]
"TARGET_ZBS"
"bclr\t%0,%1,%2"
[(set_attr "type" "bitmanip")])

(define_insn "*bclri<mode>"
[(set (match_operand:X 0 "register_operand" "=r")
(and:X (match_operand:X 1 "register_operand" "r")
(match_operand 2 "not_single_bit_mask_operand" "i")))]
"TARGET_ZBS"
"bclri\t%0,%1,%T2"
[(set_attr "type" "bitmanip")])

(define_insn "*binv<mode>"
[(set (match_operand:X 0 "register_operand" "=r")
(xor:X (ashift:X (const_int 1)
(match_operand:QI 2 "register_operand" "r"))
(match_operand:X 1 "register_operand" "r")))]
"TARGET_ZBS"
"binv\t%0,%1,%2"
[(set_attr "type" "bitmanip")])

(define_insn "*binvi<mode>"
[(set (match_operand:X 0 "register_operand" "=r")
(xor:X (match_operand:X 1 "register_operand" "r")
(match_operand 2 "single_bit_mask_operand" "i")))]
"TARGET_ZBS"
"binvi\t%0,%1,%S2"
[(set_attr "type" "bitmanip")])

(define_insn "*bext<mode>"
[(set (match_operand:X 0 "register_operand" "=r")
(zero_extract:X (match_operand:X 1 "register_operand" "r")
(const_int 1)
(zero_extend:X
(match_operand:QI 2 "register_operand" "r"))))]
"TARGET_ZBS"
"bext\t%0,%1,%2"
[(set_attr "type" "bitmanip")])

(define_insn "*bexti"
[(set (match_operand:X 0 "register_operand" "=r")
(zero_extract:X (match_operand:X 1 "register_operand" "r")
(const_int 1)
(match_operand 2 "immediate_operand" "i")))]
"TARGET_ZBS"
"bexti\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
22 changes: 22 additions & 0 deletions gcc/config/riscv/predicates.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@
if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
return false;

/* Check whether the constant can be loaded in a single
instruction with zbs extensions. */
if (TARGET_64BIT && TARGET_ZBS && SINGLE_BIT_MASK_OPERAND (INTVAL (op)))
return false;

/* Otherwise check whether the constant can be loaded in a single
instruction. */
return !LUI_OPERAND (INTVAL (op)) && !SMALL_OPERAND (INTVAL (op));
Expand Down Expand Up @@ -217,3 +222,20 @@
{
return riscv_gpr_save_operation_p (op);
})

;; Predicates for the ZBS extension.
(define_predicate "single_bit_mask_operand"
(and (match_code "const_int")
(match_test "pow2p_hwi (INTVAL (op))")))

(define_predicate "not_single_bit_mask_operand"
(and (match_code "const_int")
(match_test "pow2p_hwi (~INTVAL (op))")))

(define_predicate "const31_operand"
(and (match_code "const_int")
(match_test "INTVAL (op) == 31")))

(define_predicate "const63_operand"
(and (match_code "const_int")
(match_test "INTVAL (op) == 63")))
35 changes: 33 additions & 2 deletions gcc/config/riscv/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,13 @@ riscv_build_integer_1 (struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS],
codes[0].value = value;
return 1;
}
if (TARGET_ZBS && SINGLE_BIT_MASK_OPERAND (value))
{
/* Simply BSETI. */
codes[0].code = UNKNOWN;
codes[0].value = value;
return 1;
}

/* End with ADDI. When constructing HImode constants, do not generate any
intermediate value that is not itself a valid HImode constant. The
Expand Down Expand Up @@ -2220,7 +2227,17 @@ riscv_output_move (rtx dest, rtx src)
}

if (src_code == CONST_INT)
return "li\t%0,%1";
{
if (SMALL_OPERAND (INTVAL (src)) || LUI_OPERAND (INTVAL (src)))
return "li\t%0,%1";

if (TARGET_ZBS
&& SINGLE_BIT_MASK_OPERAND (INTVAL (src)))
return "bseti\t%0,zero,%S1";

/* Should never reach here. */
abort ();
}

if (src_code == HIGH)
return "lui\t%0,%h1";
Expand Down Expand Up @@ -3561,7 +3578,9 @@ riscv_memmodel_needs_release_fence (enum memmodel model)
'A' Print the atomic operation suffix for memory model OP.
'F' Print a FENCE if the memory model requires a release.
'z' Print x0 if OP is zero, otherwise print OP normally.
'i' Print i if the operand is not a register. */
'i' Print i if the operand is not a register.
'S' Print shift-index of single-bit mask OP.
'T' Print shift-index of inverted single-bit mask OP. */

static void
riscv_print_operand (FILE *file, rtx op, int letter)
Expand Down Expand Up @@ -3601,6 +3620,18 @@ riscv_print_operand (FILE *file, rtx op, int letter)
fputs ("i", file);
break;

case 'S':
{
rtx newop = GEN_INT (ctz_hwi (INTVAL (op)));
output_addr_const (file, newop);
break;
}
case 'T':
{
rtx newop = GEN_INT (ctz_hwi (~INTVAL (op)));
output_addr_const (file, newop);
break;
}
default:
switch (code)
{
Expand Down
8 changes: 8 additions & 0 deletions gcc/config/riscv/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,14 @@ enum reg_class
(((VALUE) | ((1UL<<31) - IMM_REACH)) == ((1UL<<31) - IMM_REACH) \
|| ((VALUE) | ((1UL<<31) - IMM_REACH)) + IMM_REACH == 0)

/* If this is a single bit mask, then we can load it with bseti. But this
is not useful for any of the low 31 bits because we can use addi or lui
to load them. It is wrong for loading SImode 0x80000000 on rv64 because it
needs to be sign-extended. So we restrict this to the upper 32-bits
only. */
#define SINGLE_BIT_MASK_OPERAND(VALUE) \
(pow2p_hwi (VALUE) && (ctz_hwi (VALUE) >= 32))

/* Stack layout; function entry, exit and calling. */

#define STACK_GROWS_DOWNWARD 1
Expand Down
4 changes: 2 additions & 2 deletions gcc/testsuite/gcc.target/riscv/zba-slliuw.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-march=rv64gc_zba -mabi=lp64 -O2" } */
/* { dg-options "-march=rv64gc_zba_zbs -mabi=lp64 -O2" } */

long
foo (long i)
Expand All @@ -8,4 +8,4 @@ foo (long i)
}
/* XXX: This pattern need combine improvement or intermediate instruction
* from zbs. */
/* { dg-final { scan-assembler-not "slli.uw" } } */
/* { dg-final { scan-assembler "slli.uw" } } */
20 changes: 20 additions & 0 deletions gcc/testsuite/gcc.target/riscv/zbs-bclr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */

/* bclr */
long
foo0 (long i, long j)
{
return i & ~(1L << j);
}

/* bclri */
long
foo1 (long i)
{
return i & ~(1L << 20);
}

/* { dg-final { scan-assembler-times "bclr\t" 1 } } */
/* { dg-final { scan-assembler-times "bclri\t" 1 } } */
/* { dg-final { scan-assembler-not "andi" } } */
20 changes: 20 additions & 0 deletions gcc/testsuite/gcc.target/riscv/zbs-bext.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */

/* bext */
long
foo0 (long i, long j)
{
return 1L & (i >> j);
}

/* bexti */
long
foo1 (long i)
{
return 1L & (i >> 20);
}

/* { dg-final { scan-assembler-times "bexti\t" 1 } } */
/* { dg-final { scan-assembler-times "bext\t" 1 } } */
/* { dg-final { scan-assembler-not "andi" } } */
20 changes: 20 additions & 0 deletions gcc/testsuite/gcc.target/riscv/zbs-binv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */

/* binv */
long
foo0 (long i, long j)
{
return i ^ (1L << j);
}

/* binvi */
long
foo1 (long i)
{
return i ^ (1L << 20);
}

/* { dg-final { scan-assembler-times "binv\t" 1 } } */
/* { dg-final { scan-assembler-times "binvi\t" 1 } } */
/* { dg-final { scan-assembler-not "andi" } } */
41 changes: 41 additions & 0 deletions gcc/testsuite/gcc.target/riscv/zbs-bset.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* { dg-do compile } */
/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */

/* bset */
long
sub0 (long i, long j)
{
return i | (1L << j);
}

/* bset_mask */
long
sub1 (long i, long j)
{
return i | (1L << (j & 0x3f));
}

/* bset_1 */
long
sub2 (long i)
{
return 1L << i;
}

/* bset_1_mask */
long
sub3 (long i)
{
return 1L << (i & 0x3f);
}

/* bseti */
long
sub4 (long i)
{
return i | (1L << 20);
}

/* { dg-final { scan-assembler-times "bset\t" 4 } } */
/* { dg-final { scan-assembler-times "bseti\t" 1 } } */
/* { dg-final { scan-assembler-not "andi" } } */

0 comments on commit 4e1e0d7

Please sign in to comment.