From d3bc6ead74d78d367c0d6cc53efc57c05d8133e9 Mon Sep 17 00:00:00 2001 From: "yilun.xie" Date: Thu, 18 Nov 2021 16:08:45 +0800 Subject: [PATCH 22/26] Implement instruction patterns for ZBS extension --- gcc/config/riscv/predicates.md | 22 +++++++++++ gcc/config/riscv/riscv.c | 37 ++++++++++++++++++- gcc/config/riscv/riscv.h | 8 ++++ gcc/testsuite/gcc.target/riscv/zba-slliuw.c | 4 +- gcc/testsuite/gcc.target/riscv/zbs-bclr.c | 20 ++++++++++ gcc/testsuite/gcc.target/riscv/zbs-bext.c | 20 ++++++++++ gcc/testsuite/gcc.target/riscv/zbs-binv.c | 20 ++++++++++ gcc/testsuite/gcc.target/riscv/zbs-bset.c | 41 +++++++++++++++++++++ 8 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-bclr.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-bext.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-binv.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-bset.c diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md index 23211513554..7a079ebd175 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -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)); @@ -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"))) \ No newline at end of file diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index 9e45c1ff9be..0978666a366 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -388,6 +388,14 @@ riscv_build_integer_1 (struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS], 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 XORI case below will handle those remaining HImode constants. */ @@ -2199,7 +2207,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"; @@ -3543,7 +3561,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) @@ -3583,6 +3603,19 @@ 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) { diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index d17096e1dfa..ff6729aedac 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -521,6 +521,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 diff --git a/gcc/testsuite/gcc.target/riscv/zba-slliuw.c b/gcc/testsuite/gcc.target/riscv/zba-slliuw.c index 55ebc1c81ce..2c86e446272 100644 --- a/gcc/testsuite/gcc.target/riscv/zba-slliuw.c +++ b/gcc/testsuite/gcc.target/riscv/zba-slliuw.c @@ -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) @@ -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" } } */ \ No newline at end of file +/* { dg-final { scan-assembler "slli.uw" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/zbs-bclr.c b/gcc/testsuite/gcc.target/riscv/zbs-bclr.c new file mode 100644 index 00000000000..fdf75b039b9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbs-bclr.c @@ -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" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/zbs-bext.c b/gcc/testsuite/gcc.target/riscv/zbs-bext.c new file mode 100644 index 00000000000..766a7c4423a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbs-bext.c @@ -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" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/zbs-binv.c b/gcc/testsuite/gcc.target/riscv/zbs-binv.c new file mode 100644 index 00000000000..d90a6301103 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbs-binv.c @@ -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" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/zbs-bset.c b/gcc/testsuite/gcc.target/riscv/zbs-bset.c new file mode 100644 index 00000000000..c3107270153 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbs-bset.c @@ -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" } } */ \ No newline at end of file -- 2.33.1