Re: [PATCH v2 1/2] riscv: Add support for strlen inline expansion
Applied to master. Thanks! Philipp. On Wed, 6 Sept 2023 at 18:07, Christoph Muellner wrote: > > From: Christoph Müllner > > This patch implements the expansion of the strlen builtin for RV32/RV64 > for xlen-aligned aligned strings if Zbb or XTheadBb instructions are > available. > The inserted sequences are: > > rv32gc_zbb (RV64 is similar): > add a3,a0,4 > li a4,-1 > .L1: lw a5,0(a0) > add a0,a0,4 > orc.b a5,a5 > beq a5,a4,.L1 > not a5,a5 > ctz a5,a5 > srl a5,a5,0x3 > add a0,a0,a5 > sub a0,a0,a3 > > rv64gc_xtheadbb (RV32 is similar): > add a4,a0,8 > .L2: lda5,0(a0) > add a0,a0,8 > th.tstnbz a5,a5 > beqz a5,.L2 > th.reva5,a5 > th.ff1a5,a5 > srl a5,a5,0x3 > add a0,a0,a5 > sub a0,a0,a4 > > This allows to inline calls to strlen(), with optimized code for > xlen-aligned strings, resulting in the following benefits over > a call to libc: > * no call/ret instructions > * no stack frame allocation > * no register saving/restoring > * no alignment test > > The inlining mechanism is gated by a new switch ('-minline-strlen') > and by the variable 'optimize_size'. > > Tested using the glibc string tests. > > Signed-off-by: Christoph Müllner > > gcc/ChangeLog: > > * config.gcc: Add new object riscv-string.o. > riscv-string.cc. > * config/riscv/riscv-protos.h (riscv_expand_strlen): > New function. > * config/riscv/riscv.md (strlen): New expand INSN. > * config/riscv/riscv.opt: New flag 'minline-strlen'. > * config/riscv/t-riscv: Add new object riscv-string.o. > * config/riscv/thead.md (th_rev2): Export INSN name. > (th_rev2): Likewise. > (th_tstnbz2): New INSN. > * doc/invoke.texi: Document '-minline-strlen'. > * emit-rtl.cc (emit_likely_jump_insn): New helper function. > (emit_unlikely_jump_insn): Likewise. > * rtl.h (emit_likely_jump_insn): New prototype. > (emit_unlikely_jump_insn): Likewise. > * config/riscv/riscv-string.cc: New file. > > gcc/testsuite/ChangeLog: > > * gcc.target/riscv/xtheadbb-strlen-unaligned.c: New test. > * gcc.target/riscv/xtheadbb-strlen.c: New test. > * gcc.target/riscv/zbb-strlen-disabled-2.c: New test. > * gcc.target/riscv/zbb-strlen-disabled.c: New test. > * gcc.target/riscv/zbb-strlen-unaligned.c: New test. > * gcc.target/riscv/zbb-strlen.c: New test. > --- > gcc/config.gcc| 3 +- > gcc/config/riscv/riscv-protos.h | 3 + > gcc/config/riscv/riscv-string.cc | 183 ++ > gcc/config/riscv/riscv.md | 28 +++ > gcc/config/riscv/riscv.opt| 4 + > gcc/config/riscv/t-riscv | 6 + > gcc/config/riscv/thead.md | 9 +- > gcc/doc/invoke.texi | 11 +- > gcc/emit-rtl.cc | 24 +++ > gcc/rtl.h | 2 + > .../riscv/xtheadbb-strlen-unaligned.c | 14 ++ > .../gcc.target/riscv/xtheadbb-strlen.c| 19 ++ > .../gcc.target/riscv/zbb-strlen-disabled-2.c | 15 ++ > .../gcc.target/riscv/zbb-strlen-disabled.c| 15 ++ > .../gcc.target/riscv/zbb-strlen-unaligned.c | 14 ++ > gcc/testsuite/gcc.target/riscv/zbb-strlen.c | 19 ++ > 16 files changed, 366 insertions(+), 3 deletions(-) > create mode 100644 gcc/config/riscv/riscv-string.cc > create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-strlen-unaligned.c > create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-strlen.c > create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-strlen-disabled-2.c > create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-strlen-disabled.c > create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-strlen-unaligned.c > create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-strlen.c > > diff --git a/gcc/config.gcc b/gcc/config.gcc > index b2fe7c7ceef..aff6b6a5601 100644 > --- a/gcc/config.gcc > +++ b/gcc/config.gcc > @@ -530,7 +530,8 @@ pru-*-*) > ;; > riscv*) > cpu_type=riscv > - extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o > riscv-shorten-memrefs.o riscv-selftests.o riscv-v.o riscv-vsetvl.o > riscv-vector-costs.o" > + extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o > riscv-shorten-memrefs.o riscv-selftests.o riscv-string.o" > + extra_objs="${extra_objs} riscv-v.o riscv-vsetvl.o > riscv-vector-costs.o" > extra_objs="${extra_objs} riscv-vector-builtins.o > riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o" > extra_objs="${extra_objs} thead.o" > d_target_objs="riscv-d.o" > diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h > index
Re: [PATCH v2 1/2] riscv: Add support for strlen inline expansion
On 9/6/23 10:07, Christoph Muellner wrote: From: Christoph Müllner This patch implements the expansion of the strlen builtin for RV32/RV64 for xlen-aligned aligned strings if Zbb or XTheadBb instructions are available. The inserted sequences are: rv32gc_zbb (RV64 is similar): add a3,a0,4 li a4,-1 .L1: lw a5,0(a0) add a0,a0,4 orc.b a5,a5 beq a5,a4,.L1 not a5,a5 ctz a5,a5 srl a5,a5,0x3 add a0,a0,a5 sub a0,a0,a3 rv64gc_xtheadbb (RV32 is similar): add a4,a0,8 .L2: lda5,0(a0) add a0,a0,8 th.tstnbz a5,a5 beqz a5,.L2 th.reva5,a5 th.ff1a5,a5 srl a5,a5,0x3 add a0,a0,a5 sub a0,a0,a4 This allows to inline calls to strlen(), with optimized code for xlen-aligned strings, resulting in the following benefits over a call to libc: * no call/ret instructions * no stack frame allocation * no register saving/restoring * no alignment test The inlining mechanism is gated by a new switch ('-minline-strlen') and by the variable 'optimize_size'. Tested using the glibc string tests. Signed-off-by: Christoph Müllner gcc/ChangeLog: * config.gcc: Add new object riscv-string.o. riscv-string.cc. * config/riscv/riscv-protos.h (riscv_expand_strlen): New function. * config/riscv/riscv.md (strlen): New expand INSN. * config/riscv/riscv.opt: New flag 'minline-strlen'. * config/riscv/t-riscv: Add new object riscv-string.o. * config/riscv/thead.md (th_rev2): Export INSN name. (th_rev2): Likewise. (th_tstnbz2): New INSN. * doc/invoke.texi: Document '-minline-strlen'. * emit-rtl.cc (emit_likely_jump_insn): New helper function. (emit_unlikely_jump_insn): Likewise. * rtl.h (emit_likely_jump_insn): New prototype. (emit_unlikely_jump_insn): Likewise. * config/riscv/riscv-string.cc: New file. gcc/testsuite/ChangeLog: * gcc.target/riscv/xtheadbb-strlen-unaligned.c: New test. * gcc.target/riscv/xtheadbb-strlen.c: New test. * gcc.target/riscv/zbb-strlen-disabled-2.c: New test. * gcc.target/riscv/zbb-strlen-disabled.c: New test. * gcc.target/riscv/zbb-strlen-unaligned.c: New test. * gcc.target/riscv/zbb-strlen.c: New test. Note that I don't think we need the new UNSPEC_STRLEN since its only used in the expander and doesn't survive into RTL. Your call on whether or not to remove it now or as a separate patch (or keep it if I'm wrong about it not being needed. OK for the trunk. Sorry this got lost in the shuffle last year. jeff .
Re: [PATCH v2 1/2] riscv: Add support for strlen inline expansion
On Wed, 06 Sep 2023 09:47:05 PDT (-0700), jeffreya...@gmail.com wrote: On 9/6/23 10:22, Palmer Dabbelt wrote: On Wed, 06 Sep 2023 09:07:33 PDT (-0700), christoph.muell...@vrull.eu wrote: From: Christoph Müllner This patch implements the expansion of the strlen builtin for RV32/RV64 for xlen-aligned aligned strings if Zbb or XTheadBb instructions are available. The inserted sequences are: rv32gc_zbb (RV64 is similar): add a3,a0,4 li a4,-1 .L1: lw a5,0(a0) add a0,a0,4 orc.b a5,a5 beq a5,a4,.L1 not a5,a5 ctz a5,a5 srl a5,a5,0x3 add a0,a0,a5 sub a0,a0,a3 rv64gc_xtheadbb (RV32 is similar): add a4,a0,8 .L2: ld a5,0(a0) add a0,a0,8 th.tstnbz a5,a5 beqz a5,.L2 th.rev a5,a5 th.ff1 a5,a5 srl a5,a5,0x3 add a0,a0,a5 sub a0,a0,a4 This allows to inline calls to strlen(), with optimized code for xlen-aligned strings, resulting in the following benefits over a call to libc: * no call/ret instructions * no stack frame allocation * no register saving/restoring * no alignment test The inlining mechanism is gated by a new switch ('-minline-strlen') and by the variable 'optimize_size'. Maybe this is more of a Jeff question, but this looks to me like something that should be target-agnostic -- maybe we need some backend work to actually emit the special instruction, but IIRC this is a somewhat common flavor of instruction and is in other ISAs as well. It looks like there's already a strlen insn, so I guess the core issue is why we need that unspec? Sorry if I'm just missing something, though... The generic strlen expansion in GCC doesn't really expand a strlen loop. It really just calls into the target code and forces the target to handle everything. OK, that explains it. We could have generic strlen expansion code that kicks in if the target expander fails. And we could probably create the necessary opcodes to express the optimized end-of-string comparison instructions that exist on various architectures. I'm not not sure it's worth that much effort given targets are already doing their own strlen expansions. If everyone does it this way then I don't think we need to worry about it. jeff
Re: [PATCH v2 1/2] riscv: Add support for strlen inline expansion
On 9/6/23 10:22, Palmer Dabbelt wrote: On Wed, 06 Sep 2023 09:07:33 PDT (-0700), christoph.muell...@vrull.eu wrote: From: Christoph Müllner This patch implements the expansion of the strlen builtin for RV32/RV64 for xlen-aligned aligned strings if Zbb or XTheadBb instructions are available. The inserted sequences are: rv32gc_zbb (RV64 is similar): add a3,a0,4 li a4,-1 .L1: lw a5,0(a0) add a0,a0,4 orc.b a5,a5 beq a5,a4,.L1 not a5,a5 ctz a5,a5 srl a5,a5,0x3 add a0,a0,a5 sub a0,a0,a3 rv64gc_xtheadbb (RV32 is similar): add a4,a0,8 .L2: ld a5,0(a0) add a0,a0,8 th.tstnbz a5,a5 beqz a5,.L2 th.rev a5,a5 th.ff1 a5,a5 srl a5,a5,0x3 add a0,a0,a5 sub a0,a0,a4 This allows to inline calls to strlen(), with optimized code for xlen-aligned strings, resulting in the following benefits over a call to libc: * no call/ret instructions * no stack frame allocation * no register saving/restoring * no alignment test The inlining mechanism is gated by a new switch ('-minline-strlen') and by the variable 'optimize_size'. Maybe this is more of a Jeff question, but this looks to me like something that should be target-agnostic -- maybe we need some backend work to actually emit the special instruction, but IIRC this is a somewhat common flavor of instruction and is in other ISAs as well. It looks like there's already a strlen insn, so I guess the core issue is why we need that unspec? Sorry if I'm just missing something, though... The generic strlen expansion in GCC doesn't really expand a strlen loop. It really just calls into the target code and forces the target to handle everything. We could have generic strlen expansion code that kicks in if the target expander fails. And we could probably create the necessary opcodes to express the optimized end-of-string comparison instructions that exist on various architectures. I'm not not sure it's worth that much effort given targets are already doing their own strlen expansions. jeff
Re: [PATCH v2 1/2] riscv: Add support for strlen inline expansion
On Wed, 06 Sep 2023 09:07:33 PDT (-0700), christoph.muell...@vrull.eu wrote: From: Christoph Müllner This patch implements the expansion of the strlen builtin for RV32/RV64 for xlen-aligned aligned strings if Zbb or XTheadBb instructions are available. The inserted sequences are: rv32gc_zbb (RV64 is similar): add a3,a0,4 li a4,-1 .L1: lw a5,0(a0) add a0,a0,4 orc.b a5,a5 beq a5,a4,.L1 not a5,a5 ctz a5,a5 srl a5,a5,0x3 add a0,a0,a5 sub a0,a0,a3 rv64gc_xtheadbb (RV32 is similar): add a4,a0,8 .L2: lda5,0(a0) add a0,a0,8 th.tstnbz a5,a5 beqz a5,.L2 th.reva5,a5 th.ff1a5,a5 srl a5,a5,0x3 add a0,a0,a5 sub a0,a0,a4 This allows to inline calls to strlen(), with optimized code for xlen-aligned strings, resulting in the following benefits over a call to libc: * no call/ret instructions * no stack frame allocation * no register saving/restoring * no alignment test The inlining mechanism is gated by a new switch ('-minline-strlen') and by the variable 'optimize_size'. Maybe this is more of a Jeff question, but this looks to me like something that should be target-agnostic -- maybe we need some backend work to actually emit the special instruction, but IIRC this is a somewhat common flavor of instruction and is in other ISAs as well. It looks like there's already a strlen insn, so I guess the core issue is why we need that unspec? Sorry if I'm just missing something, though... Tested using the glibc string tests. Signed-off-by: Christoph Müllner gcc/ChangeLog: * config.gcc: Add new object riscv-string.o. riscv-string.cc. * config/riscv/riscv-protos.h (riscv_expand_strlen): New function. * config/riscv/riscv.md (strlen): New expand INSN. * config/riscv/riscv.opt: New flag 'minline-strlen'. * config/riscv/t-riscv: Add new object riscv-string.o. * config/riscv/thead.md (th_rev2): Export INSN name. (th_rev2): Likewise. (th_tstnbz2): New INSN. * doc/invoke.texi: Document '-minline-strlen'. * emit-rtl.cc (emit_likely_jump_insn): New helper function. (emit_unlikely_jump_insn): Likewise. * rtl.h (emit_likely_jump_insn): New prototype. (emit_unlikely_jump_insn): Likewise. * config/riscv/riscv-string.cc: New file. gcc/testsuite/ChangeLog: * gcc.target/riscv/xtheadbb-strlen-unaligned.c: New test. * gcc.target/riscv/xtheadbb-strlen.c: New test. * gcc.target/riscv/zbb-strlen-disabled-2.c: New test. * gcc.target/riscv/zbb-strlen-disabled.c: New test. * gcc.target/riscv/zbb-strlen-unaligned.c: New test. * gcc.target/riscv/zbb-strlen.c: New test. --- gcc/config.gcc| 3 +- gcc/config/riscv/riscv-protos.h | 3 + gcc/config/riscv/riscv-string.cc | 183 ++ gcc/config/riscv/riscv.md | 28 +++ gcc/config/riscv/riscv.opt| 4 + gcc/config/riscv/t-riscv | 6 + gcc/config/riscv/thead.md | 9 +- gcc/doc/invoke.texi | 11 +- gcc/emit-rtl.cc | 24 +++ gcc/rtl.h | 2 + .../riscv/xtheadbb-strlen-unaligned.c | 14 ++ .../gcc.target/riscv/xtheadbb-strlen.c| 19 ++ .../gcc.target/riscv/zbb-strlen-disabled-2.c | 15 ++ .../gcc.target/riscv/zbb-strlen-disabled.c| 15 ++ .../gcc.target/riscv/zbb-strlen-unaligned.c | 14 ++ gcc/testsuite/gcc.target/riscv/zbb-strlen.c | 19 ++ 16 files changed, 366 insertions(+), 3 deletions(-) create mode 100644 gcc/config/riscv/riscv-string.cc create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-strlen-unaligned.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-strlen.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-strlen-disabled-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-strlen-disabled.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-strlen-unaligned.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-strlen.c diff --git a/gcc/config.gcc b/gcc/config.gcc index b2fe7c7ceef..aff6b6a5601 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -530,7 +530,8 @@ pru-*-*) ;; riscv*) cpu_type=riscv - extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-v.o riscv-vsetvl.o riscv-vector-costs.o" + extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-string.o" + extra_objs="${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector-costs.o" extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o"
[PATCH v2 1/2] riscv: Add support for strlen inline expansion
From: Christoph Müllner This patch implements the expansion of the strlen builtin for RV32/RV64 for xlen-aligned aligned strings if Zbb or XTheadBb instructions are available. The inserted sequences are: rv32gc_zbb (RV64 is similar): add a3,a0,4 li a4,-1 .L1: lw a5,0(a0) add a0,a0,4 orc.b a5,a5 beq a5,a4,.L1 not a5,a5 ctz a5,a5 srl a5,a5,0x3 add a0,a0,a5 sub a0,a0,a3 rv64gc_xtheadbb (RV32 is similar): add a4,a0,8 .L2: lda5,0(a0) add a0,a0,8 th.tstnbz a5,a5 beqz a5,.L2 th.reva5,a5 th.ff1a5,a5 srl a5,a5,0x3 add a0,a0,a5 sub a0,a0,a4 This allows to inline calls to strlen(), with optimized code for xlen-aligned strings, resulting in the following benefits over a call to libc: * no call/ret instructions * no stack frame allocation * no register saving/restoring * no alignment test The inlining mechanism is gated by a new switch ('-minline-strlen') and by the variable 'optimize_size'. Tested using the glibc string tests. Signed-off-by: Christoph Müllner gcc/ChangeLog: * config.gcc: Add new object riscv-string.o. riscv-string.cc. * config/riscv/riscv-protos.h (riscv_expand_strlen): New function. * config/riscv/riscv.md (strlen): New expand INSN. * config/riscv/riscv.opt: New flag 'minline-strlen'. * config/riscv/t-riscv: Add new object riscv-string.o. * config/riscv/thead.md (th_rev2): Export INSN name. (th_rev2): Likewise. (th_tstnbz2): New INSN. * doc/invoke.texi: Document '-minline-strlen'. * emit-rtl.cc (emit_likely_jump_insn): New helper function. (emit_unlikely_jump_insn): Likewise. * rtl.h (emit_likely_jump_insn): New prototype. (emit_unlikely_jump_insn): Likewise. * config/riscv/riscv-string.cc: New file. gcc/testsuite/ChangeLog: * gcc.target/riscv/xtheadbb-strlen-unaligned.c: New test. * gcc.target/riscv/xtheadbb-strlen.c: New test. * gcc.target/riscv/zbb-strlen-disabled-2.c: New test. * gcc.target/riscv/zbb-strlen-disabled.c: New test. * gcc.target/riscv/zbb-strlen-unaligned.c: New test. * gcc.target/riscv/zbb-strlen.c: New test. --- gcc/config.gcc| 3 +- gcc/config/riscv/riscv-protos.h | 3 + gcc/config/riscv/riscv-string.cc | 183 ++ gcc/config/riscv/riscv.md | 28 +++ gcc/config/riscv/riscv.opt| 4 + gcc/config/riscv/t-riscv | 6 + gcc/config/riscv/thead.md | 9 +- gcc/doc/invoke.texi | 11 +- gcc/emit-rtl.cc | 24 +++ gcc/rtl.h | 2 + .../riscv/xtheadbb-strlen-unaligned.c | 14 ++ .../gcc.target/riscv/xtheadbb-strlen.c| 19 ++ .../gcc.target/riscv/zbb-strlen-disabled-2.c | 15 ++ .../gcc.target/riscv/zbb-strlen-disabled.c| 15 ++ .../gcc.target/riscv/zbb-strlen-unaligned.c | 14 ++ gcc/testsuite/gcc.target/riscv/zbb-strlen.c | 19 ++ 16 files changed, 366 insertions(+), 3 deletions(-) create mode 100644 gcc/config/riscv/riscv-string.cc create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-strlen-unaligned.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-strlen.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-strlen-disabled-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-strlen-disabled.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-strlen-unaligned.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-strlen.c diff --git a/gcc/config.gcc b/gcc/config.gcc index b2fe7c7ceef..aff6b6a5601 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -530,7 +530,8 @@ pru-*-*) ;; riscv*) cpu_type=riscv - extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-v.o riscv-vsetvl.o riscv-vector-costs.o" + extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-string.o" + extra_objs="${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector-costs.o" extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o" extra_objs="${extra_objs} thead.o" d_target_objs="riscv-d.o" diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 6dbf6b9f943..b060d047f01 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -517,6 +517,9 @@ const unsigned int RISCV_BUILTIN_SHIFT = 1; /* Mask that selects the riscv_builtin_class part of a function code. */ const unsigned int RISCV_BUILTIN_CLASS = (1 << RISCV_BUILTIN_SHIFT) - 1; +/* Routines implemented