diff options
author | Jim Wilson <jimw@sifive.com> | 2021-08-31 11:42:26 +0800 |
---|---|---|
committer | Kito Cheng <kito.cheng@sifive.com> | 2021-10-25 17:06:40 +0800 |
commit | e596a283e54bdb0b4a0cebc128f9d9ac268e3916 (patch) | |
tree | d5811d683ed11e0aa17520d8c36e8dd228a26fe6 /gcc | |
parent | 04a9b554ba1a71baae6f985905d92fe693acb437 (diff) | |
download | gcc-e596a283e54bdb0b4a0cebc128f9d9ac268e3916.zip gcc-e596a283e54bdb0b4a0cebc128f9d9ac268e3916.tar.gz gcc-e596a283e54bdb0b4a0cebc128f9d9ac268e3916.tar.bz2 |
RISC-V: Implement instruction patterns for ZBB extension.
2021-10-25 Jim Wilson <jimw@sifive.com>
Kito Cheng <kito.cheng@sifive.com>
Jia-Wei Chen <jiawei@iscas.ac.cn>
gcc/ChangeLog:
* config/riscv/bitmanip.md (bitmanip_bitwise): New.
(bitmanip_minmax): New.
(clz_ctz_pcnt): New.
(bitmanip_optab): New.
(bitmanip_insn): New.
(*<optab>_not<mode>): New.
(*xor_not<mode>): New.
(<bitmanip_optab>si2): New.
(*<bitmanip_optab>disi2): New.
(<bitmanip_optab>di2): New.
(*zero_extendhi<GPR:mode>2_bitmanip): New.
(*extend<SHORT:mode><SUPERQI:mode>2_zbb): New.
(*zero_extendhi<GPR:mode>2_zbb): New.
(rotrsi3): New.
(rotrdi3): New.
(rotrsi3_sext): New.
(rotlsi3): New.
(rotldi3): New.
(rotlsi3_sext): New.
(bswap<mode>2): New.
(<bitmanip_optab><mode>3): New.
* config/riscv/riscv.md (type): Add rotate.
(zero_extendhi<GPR:mode>2): Change to define_expand pattern.
(*zero_extendhi<GPR:mode>2): New.
(extend<SHORT:mode><SUPERQI:mode>2): Change to define_expand pattern.
(*extend<SHORT:mode><SUPERQI:mode>2): New.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/zbb-andn-orn-xnor-01.c: New.
* gcc.target/riscv/zbb-andn-orn-xnor-02.c: Ditto.
* gcc.target/riscv/zbb-min-max.c: Ditto.
* gcc.target/riscv/zbb-rol-ror-01.c: Ditto.
* gcc.target/riscv/zbb-rol-ror-02.c: Ditto.
* gcc.target/riscv/zbb-rol-ror-03.c: Ditto.
* gcc.target/riscv/zbbw.c: Ditto.
Co-authored-by: Kito Cheng <kito.cheng@sifive.com>
Co-authored-by: Jia-Wei Chen <jiawei@iscas.ac.cn>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/riscv/bitmanip.md | 164 | ||||
-rw-r--r-- | gcc/config/riscv/riscv.md | 21 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/zbb-andn-orn-xnor-01.c | 21 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/zbb-andn-orn-xnor-02.c | 21 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/zbb-min-max.c | 31 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/zbb-rol-ror-01.c | 16 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/zbb-rol-ror-02.c | 16 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/zbb-rol-ror-03.c | 17 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/zbbw.c | 25 |
9 files changed, 327 insertions, 5 deletions
diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index 3849d21..4d62451 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -17,6 +17,30 @@ ;; along with GCC; see the file COPYING3. If not see ;; <http://www.gnu.org/licenses/>. +(define_code_iterator bitmanip_bitwise [and ior]) + +(define_code_iterator bitmanip_minmax [smin umin smax umax]) + +(define_code_iterator clz_ctz_pcnt [clz ctz popcount]) + +(define_code_attr bitmanip_optab [(smin "smin") + (smax "smax") + (umin "umin") + (umax "umax") + (clz "clz") + (ctz "ctz") + (popcount "popcount")]) + + +(define_code_attr bitmanip_insn [(smin "min") + (smax "max") + (umin "minu") + (umax "maxu") + (clz "clz") + (ctz "ctz") + (popcount "cpop")]) + + ;; ZBA extension. (define_insn "*zero_extendsidi2_bitmanip" @@ -74,3 +98,143 @@ "slli.uw\t%0,%1,%2" [(set_attr "type" "bitmanip") (set_attr "mode" "DI")]) + +;; ZBB extension. + +(define_insn "*<optab>_not<mode>" + [(set (match_operand:X 0 "register_operand" "=r") + (bitmanip_bitwise:X (not:X (match_operand:X 1 "register_operand" "r")) + (match_operand:X 2 "register_operand" "r")))] + "TARGET_ZBB" + "<insn>n\t%0,%2,%1" + [(set_attr "type" "bitmanip") + (set_attr "mode" "<X:MODE>")]) + +(define_insn "*xor_not<mode>" + [(set (match_operand:X 0 "register_operand" "=r") + (not:X (xor:X (match_operand:X 1 "register_operand" "r") + (match_operand:X 2 "register_operand" "r"))))] + "TARGET_ZBB" + "xnor\t%0,%1,%2" + [(set_attr "type" "bitmanip") + (set_attr "mode" "<X:MODE>")]) + +(define_insn "<bitmanip_optab>si2" + [(set (match_operand:SI 0 "register_operand" "=r") + (clz_ctz_pcnt:SI (match_operand:SI 1 "register_operand" "r")))] + "TARGET_ZBB" + { return TARGET_64BIT ? "<bitmanip_insn>w\t%0,%1" : "<bitmanip_insn>\t%0,%1"; } + [(set_attr "type" "bitmanip") + (set_attr "mode" "SI")]) + +(define_insn "*<bitmanip_optab>disi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI + (clz_ctz_pcnt:SI (match_operand:SI 1 "register_operand" "r"))))] + "TARGET_64BIT && TARGET_ZBB" + "<bitmanip_insn>w\t%0,%1" + [(set_attr "type" "bitmanip") + (set_attr "mode" "SI")]) + +(define_insn "<bitmanip_optab>di2" + [(set (match_operand:DI 0 "register_operand" "=r") + (clz_ctz_pcnt:DI (match_operand:DI 1 "register_operand" "r")))] + "TARGET_64BIT && TARGET_ZBB" + "<bitmanip_insn>\t%0,%1" + [(set_attr "type" "bitmanip") + (set_attr "mode" "DI")]) + +(define_insn "*zero_extendhi<GPR:mode>2_bitmanip" + [(set (match_operand:GPR 0 "register_operand" "=r,r") + (zero_extend:GPR (match_operand:HI 1 "nonimmediate_operand" "r,m")))] + "TARGET_ZBB" + "@ + zext.h\t%0,%1 + lhu\t%0,%1" + [(set_attr "type" "bitmanip,load") + (set_attr "mode" "<GPR:MODE>")]) + +(define_insn "*extend<SHORT:mode><SUPERQI:mode>2_zbb" + [(set (match_operand:SUPERQI 0 "register_operand" "=r,r") + (sign_extend:SUPERQI + (match_operand:SHORT 1 "nonimmediate_operand" " r,m")))] + "TARGET_ZBB" + "@ + sext.<SHORT:size>\t%0,%1 + l<SHORT:size>\t%0,%1" + [(set_attr "type" "bitmanip,load") + (set_attr "mode" "<SUPERQI:MODE>")]) + +(define_insn "*zero_extendhi<GPR:mode>2_zbb" + [(set (match_operand:GPR 0 "register_operand" "=r,r") + (zero_extend:GPR + (match_operand:HI 1 "nonimmediate_operand" " r,m")))] + "TARGET_ZBB" + "@ + zext.h\t%0,%1 + lhu\t%0,%1" + [(set_attr "type" "bitmanip,load") + (set_attr "mode" "HI")]) + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotatert:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:QI 2 "arith_operand" "rI")))] + "TARGET_ZBB" + { return TARGET_64BIT ? "ror%i2w\t%0,%1,%2" : "ror%i2\t%0,%1,%2"; } + [(set_attr "type" "bitmanip")]) + +(define_insn "rotrdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (rotatert:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:QI 2 "arith_operand" "rI")))] + "TARGET_64BIT && TARGET_ZBB" + "ror%i2\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + +(define_insn "rotrsi3_sext" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI (rotatert:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:QI 2 "register_operand" "r"))))] + "TARGET_64BIT && TARGET_ZBB" + "rorw\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotate:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:QI 2 "register_operand" "r")))] + "TARGET_ZBB" + { return TARGET_64BIT ? "rolw\t%0,%1,%2" : "rol\t%0,%1,%2"; } + [(set_attr "type" "bitmanip")]) + +(define_insn "rotldi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (rotate:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:QI 2 "register_operand" "r")))] + "TARGET_64BIT && TARGET_ZBB" + "rol\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + +(define_insn "rotlsi3_sext" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI (rotate:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:QI 2 "register_operand" "r"))))] + "TARGET_64BIT && TARGET_ZBB" + "rolw\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + +(define_insn "bswap<mode>2" + [(set (match_operand:X 0 "register_operand" "=r") + (bswap:X (match_operand:X 1 "register_operand" "r")))] + "TARGET_64BIT && TARGET_ZBB" + "rev8\t%0,%1" + [(set_attr "type" "bitmanip")]) + +(define_insn "<bitmanip_optab><mode>3" + [(set (match_operand:X 0 "register_operand" "=r") + (bitmanip_minmax:X (match_operand:X 1 "register_operand" "r") + (match_operand:X 2 "register_operand" "r")))] + "TARGET_ZBB" + "<bitmanip_insn>\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 904d6a0..dd4c242 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -170,7 +170,7 @@ (define_attr "type" "unknown,branch,jump,call,load,fpload,store,fpstore, mtc,mfc,const,arith,logical,shift,slt,imul,idiv,move,fmove,fadd,fmul, - fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,sfb_alu,nop,ghost,bitmanip" + fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,sfb_alu,nop,ghost,bitmanip,rotate" (cond [(eq_attr "got" "load") (const_string "load") ;; If a doubleword move uses these expensive instructions, @@ -1326,11 +1326,17 @@ [(set_attr "move_type" "shift_shift,load") (set_attr "mode" "DI")]) -(define_insn_and_split "zero_extendhi<GPR:mode>2" +(define_expand "zero_extendhi<GPR:mode>2" + [(set (match_operand:GPR 0 "register_operand") + (zero_extend:GPR + (match_operand:HI 1 "nonimmediate_operand")))] + "") + +(define_insn_and_split "*zero_extendhi<GPR:mode>2" [(set (match_operand:GPR 0 "register_operand" "=r,r") (zero_extend:GPR (match_operand:HI 1 "nonimmediate_operand" " r,m")))] - "" + "!TARGET_ZBB" "@ # lhu\t%0,%1" @@ -1377,11 +1383,16 @@ [(set_attr "move_type" "move,load") (set_attr "mode" "DI")]) -(define_insn_and_split "extend<SHORT:mode><SUPERQI:mode>2" +(define_expand "extend<SHORT:mode><SUPERQI:mode>2" + [(set (match_operand:SUPERQI 0 "register_operand") + (sign_extend:SUPERQI (match_operand:SHORT 1 "nonimmediate_operand")))] + "") + +(define_insn_and_split "*extend<SHORT:mode><SUPERQI:mode>2" [(set (match_operand:SUPERQI 0 "register_operand" "=r,r") (sign_extend:SUPERQI (match_operand:SHORT 1 "nonimmediate_operand" " r,m")))] - "" + "!TARGET_ZBB" "@ # l<SHORT:size>\t%0,%1" diff --git a/gcc/testsuite/gcc.target/riscv/zbb-andn-orn-xnor-01.c b/gcc/testsuite/gcc.target/riscv/zbb-andn-orn-xnor-01.c new file mode 100644 index 0000000..0037dea --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbb-andn-orn-xnor-01.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbb -mabi=lp64 -O2" } */ + +unsigned long long foo1(unsigned long long rs1, unsigned long long rs2) +{ +return rs1 & ~rs2; +} + +unsigned long long foo2(unsigned long long rs1, unsigned long long rs2) +{ +return rs1 | ~rs2; +} + +unsigned long long foo3(unsigned long long rs1, unsigned long long rs2) +{ +return rs1 ^ ~rs2; +} + +/* { dg-final { scan-assembler-times "andn" 2 } } */ +/* { dg-final { scan-assembler-times "orn" 2 } } */ +/* { dg-final { scan-assembler-times "xnor" 2 } } */
\ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/zbb-andn-orn-xnor-02.c b/gcc/testsuite/gcc.target/riscv/zbb-andn-orn-xnor-02.c new file mode 100644 index 0000000..b0c1e40 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbb-andn-orn-xnor-02.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zbb -mabi=ilp32 -O2" } */ + +unsigned int foo1(unsigned int rs1, unsigned int rs2) +{ +return rs1 & ~rs2; +} + +unsigned int foo2(unsigned int rs1, unsigned int rs2) +{ +return rs1 | ~rs2; +} + +unsigned int foo3(unsigned int rs1, unsigned int rs2) +{ +return rs1 ^ ~rs2; +} + +/* { dg-final { scan-assembler-times "andn" 2 } } */ +/* { dg-final { scan-assembler-times "orn" 2 } } */ +/* { dg-final { scan-assembler-times "xnor" 2 } } */
\ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/zbb-min-max.c b/gcc/testsuite/gcc.target/riscv/zbb-min-max.c new file mode 100644 index 0000000..f44c398 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbb-min-max.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbb -mabi=lp64 -O2" } */ + +long +foo1 (long i, long j) +{ + return i < j ? i : j; +} + +long +foo2 (long i, long j) +{ + return i > j ? i : j; +} + +unsigned long +foo3 (unsigned long i, unsigned long j) +{ + return i < j ? i : j; +} + +unsigned long +foo4 (unsigned long i, unsigned long j) +{ + return i > j ? i : j; +} + +/* { dg-final { scan-assembler-times "min" 3 } } */ +/* { dg-final { scan-assembler-times "max" 3 } } */ +/* { dg-final { scan-assembler-times "minu" 1 } } */ +/* { dg-final { scan-assembler-times "maxu" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-01.c b/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-01.c new file mode 100644 index 0000000..9589662 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-01.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbb -mabi=lp64 -O2" } */ + +unsigned long foo1(unsigned long rs1, unsigned long rs2) +{ + long shamt = rs2 & (64 - 1); + return (rs1 << shamt) | (rs1 >> ((64 - shamt) & (64 - 1))); +} +unsigned long foo2(unsigned long rs1, unsigned long rs2) +{ + unsigned long shamt = rs2 & (64 - 1); + return (rs1 >> shamt) | (rs1 << ((64 - shamt) & (64 - 1))); +} + +/* { dg-final { scan-assembler-times "rol" 2 } } */ +/* { dg-final { scan-assembler-times "ror" 2 } } */
\ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-02.c b/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-02.c new file mode 100644 index 0000000..24b482f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-02.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zbb -mabi=ilp32 -O2" } */ + +unsigned int foo1(unsigned int rs1, unsigned int rs2) +{ + unsigned int shamt = rs2 & (32 - 1); + return (rs1 << shamt) | (rs1 >> ((32 - shamt) & (32 - 1))); +} +unsigned int foo2(unsigned int rs1, unsigned int rs2) +{ + unsigned int shamt = rs2 & (32 - 1); + return (rs1 >> shamt) | (rs1 << ((32 - shamt) & (32 - 1))); +} + +/* { dg-final { scan-assembler-times "rol" 2 } } */ +/* { dg-final { scan-assembler-times "ror" 2 } } */
\ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-03.c b/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-03.c new file mode 100644 index 0000000..ffde7c9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-03.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbb -mabi=lp64 -O2" } */ + +/* RV64 only*/ +unsigned int rol(unsigned int rs1, unsigned int rs2) +{ + int shamt = rs2 & (32 - 1); + return (rs1 << shamt) | (rs1 >> ((64 - shamt) & (32 - 1))); +} +unsigned int ror(unsigned int rs1, unsigned int rs2) +{ + int shamt = rs2 & (64 - 1); + return (rs1 >> shamt) | (rs1 << ((32 - shamt) & (32 - 1))); +} + +/* { dg-final { scan-assembler-times "rolw" 1 } } */ +/* { dg-final { scan-assembler-times "rorw" 1 } } */
\ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/zbbw.c b/gcc/testsuite/gcc.target/riscv/zbbw.c new file mode 100644 index 0000000..236ddf7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbbw.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbb -mabi=lp64 -O2" } */ + +int +clz (int i) +{ + return __builtin_clz (i); +} + +int +ctz (int i) +{ + return __builtin_ctz (i); +} + +int +popcount (int i) +{ + return __builtin_popcount (i); +} + + +/* { dg-final { scan-assembler-times "clzw" 1 } } */ +/* { dg-final { scan-assembler-times "ctzw" 1 } } */ +/* { dg-final { scan-assembler-times "cpopw" 1 } } */ |