Message ID | 20240308172201.33853-1-david.faust@oracle.com |
---|---|
State | New |
Headers | show |
Series | [v2] bpf: add size threshold for inlining mem builtins | expand |
Hi Faust. OK. Thanks! > [Changes from v1: > - Error if threshold is exceeded instead of silently emitting libcall > - Update test accordingly > - Expand documentation to explain this behavior ] > > BPF cannot fall back on library calls to implement memmove, memcpy and > memset, so we attempt to expand these inline always if possible. > However, this inline expansion was being attempted even for excessively > large operations, which could result in gcc consuming huge amounts of > memory and hanging. > > Add a size threshold in the BPF backend below which to always expand > these operations inline, and introduce an option > -minline-memops-threshold= to control the threshold. Defaults to > 1024 bytes. > > gcc/ > > * config/bpf/bpf.cc (bpf_expand_cpymem, bpf_expand_setmem): Do > not attempt inline expansion if size is above threshold. > * config/bpf/bpf.opt (-minline-memops-threshold): New option. > * doc/invoke.texi (eBPF Options) <-minline-memops-threshold>: > Document. > > gcc/testsuite/ > > * gcc.target/bpf/inline-memops-threshold-1.c: New test. > * gcc.target/bpf/inline-memops-threshold-2.c: New test. > --- > gcc/config/bpf/bpf.cc | 26 ++++++++++++++++++- > gcc/config/bpf/bpf.opt | 4 +++ > gcc/doc/invoke.texi | 11 +++++++- > .../bpf/inline-memops-threshold-1.c | 15 +++++++++++ > .../bpf/inline-memops-threshold-2.c | 11 ++++++++ > 5 files changed, 65 insertions(+), 2 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/bpf/inline-memops-threshold-1.c > create mode 100644 gcc/testsuite/gcc.target/bpf/inline-memops-threshold-2.c > > diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc > index 0e33f4347ba..8365cd9fcb1 100644 > --- a/gcc/config/bpf/bpf.cc > +++ b/gcc/config/bpf/bpf.cc > @@ -1244,9 +1244,9 @@ bool > bpf_expand_cpymem (rtx *operands, bool is_move) > { > /* Size must be constant for this expansion to work. */ > + const char *name = is_move ? "memmove" : "memcpy"; > if (!CONST_INT_P (operands[2])) > { > - const char *name = is_move ? "memmove" : "memcpy"; > if (flag_building_libgcc) > warning (0, "could not inline call to %<__builtin_%s%>: " > "size must be constant", name); > @@ -1275,6 +1275,18 @@ bpf_expand_cpymem (rtx *operands, bool is_move) > gcc_unreachable (); > } > > + /* For sizes above threshold, always use a libcall. */ > + if (size_bytes > (unsigned HOST_WIDE_INT) bpf_inline_memops_threshold) > + { > + if (flag_building_libgcc) > + warning (0, "could not inline call to %<__builtin_%s%>: " > + "too many bytes, use -minline-memops-threshold", name); > + else > + error ("could not inline call to %<__builtin_%s%>: " > + "too many bytes, use -minline-memops-threshold", name); > + return false; > + } > + > unsigned iters = size_bytes >> ceil_log2 (align); > unsigned remainder = size_bytes & (align - 1); > > @@ -1347,6 +1359,18 @@ bpf_expand_setmem (rtx *operands) > gcc_unreachable (); > } > > + /* For sizes above threshold, always use a libcall. */ > + if (size_bytes > (unsigned HOST_WIDE_INT) bpf_inline_memops_threshold) > + { > + if (flag_building_libgcc) > + warning (0, "could not inline call to %<__builtin_memset%>: " > + "too many bytes, use -minline-memops-threshold"); > + else > + error ("could not inline call to %<__builtin_memset%>: " > + "too many bytes, use -minline-memops-threshold"); > + return false; > + } > + > unsigned iters = size_bytes >> ceil_log2 (align); > unsigned remainder = size_bytes & (align - 1); > unsigned inc = GET_MODE_SIZE (mode); > diff --git a/gcc/config/bpf/bpf.opt b/gcc/config/bpf/bpf.opt > index acfddebdad7..541ebe4dfc4 100644 > --- a/gcc/config/bpf/bpf.opt > +++ b/gcc/config/bpf/bpf.opt > @@ -108,3 +108,7 @@ Enum(asm_dialect) String(normal) Value(ASM_NORMAL) > > EnumValue > Enum(asm_dialect) String(pseudoc) Value(ASM_PSEUDOC) > + > +minline-memops-threshold= > +Target RejectNegative Joined UInteger Var(bpf_inline_memops_threshold) Init(1024) > +-minline-memops-threshold=<number> Maximum size of memset/memmove/memcpy to inline, larger sizes will use a library call. > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index c0d604a2c5c..85c938d4a14 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -971,7 +971,7 @@ Objective-C and Objective-C++ Dialects}. > @gccoptlist{-mbig-endian -mlittle-endian > -mframe-limit=@var{bytes} -mxbpf -mco-re -mno-co-re -mjmpext > -mjmp32 -malu32 -mv3-atomics -mbswap -msdiv -msmov -mcpu=@var{version} > --masm=@var{dialect}} > +-masm=@var{dialect} -minline-memops-threshold=@var{bytes}} > > @emph{FR30 Options} > @gccoptlist{-msmall-model -mno-lsim} > @@ -25701,6 +25701,15 @@ Outputs pseudo-c assembly dialect. > > @end table > > +@opindex -minline-memops-threshold > +@item -minline-memops-threshold=@var{bytes} > +Specifies a size threshold in bytes at or below which memmove, memcpy > +and memset shall always be expanded inline. Operations dealing with > +sizes larger than this threshold would have to be be implemented using > +a library call instead of being expanded inline, but since BPF doesn't > +allow libcalls, exceeding this threshold results in a compile-time > +error. The default is @samp{1024} bytes. > + > @end table > > @node FR30 Options > diff --git a/gcc/testsuite/gcc.target/bpf/inline-memops-threshold-1.c b/gcc/testsuite/gcc.target/bpf/inline-memops-threshold-1.c > new file mode 100644 > index 00000000000..c2ba4db5b7b > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/inline-memops-threshold-1.c > @@ -0,0 +1,15 @@ > + > +/* { dg-do compile } */ > +/* { dg-options "-O2" "-minline-memops-threshold=256"} */ > + > +char buf[512]; > + > +void > +mov_small (void) > +{ > + __builtin_memmove (buf, buf + 2, 255); > +} > + > +/* { dg-final { scan-assembler-not "call" } } */ > +/* { dg-final { scan-assembler "ldxb" } } */ > +/* { dg-final { scan-assembler "stxb" } } */ > diff --git a/gcc/testsuite/gcc.target/bpf/inline-memops-threshold-2.c b/gcc/testsuite/gcc.target/bpf/inline-memops-threshold-2.c > new file mode 100644 > index 00000000000..50910483890 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/bpf/inline-memops-threshold-2.c > @@ -0,0 +1,11 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -minline-memops-threshold=256" } */ > + > +char buf[512]; > + > +void > +mov_big (void) > +{ > + __builtin_memmove (buf, buf + 12, 354); /* { dg-error "too many bytes" } */ > +} > +
diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc index 0e33f4347ba..8365cd9fcb1 100644 --- a/gcc/config/bpf/bpf.cc +++ b/gcc/config/bpf/bpf.cc @@ -1244,9 +1244,9 @@ bool bpf_expand_cpymem (rtx *operands, bool is_move) { /* Size must be constant for this expansion to work. */ + const char *name = is_move ? "memmove" : "memcpy"; if (!CONST_INT_P (operands[2])) { - const char *name = is_move ? "memmove" : "memcpy"; if (flag_building_libgcc) warning (0, "could not inline call to %<__builtin_%s%>: " "size must be constant", name); @@ -1275,6 +1275,18 @@ bpf_expand_cpymem (rtx *operands, bool is_move) gcc_unreachable (); } + /* For sizes above threshold, always use a libcall. */ + if (size_bytes > (unsigned HOST_WIDE_INT) bpf_inline_memops_threshold) + { + if (flag_building_libgcc) + warning (0, "could not inline call to %<__builtin_%s%>: " + "too many bytes, use -minline-memops-threshold", name); + else + error ("could not inline call to %<__builtin_%s%>: " + "too many bytes, use -minline-memops-threshold", name); + return false; + } + unsigned iters = size_bytes >> ceil_log2 (align); unsigned remainder = size_bytes & (align - 1); @@ -1347,6 +1359,18 @@ bpf_expand_setmem (rtx *operands) gcc_unreachable (); } + /* For sizes above threshold, always use a libcall. */ + if (size_bytes > (unsigned HOST_WIDE_INT) bpf_inline_memops_threshold) + { + if (flag_building_libgcc) + warning (0, "could not inline call to %<__builtin_memset%>: " + "too many bytes, use -minline-memops-threshold"); + else + error ("could not inline call to %<__builtin_memset%>: " + "too many bytes, use -minline-memops-threshold"); + return false; + } + unsigned iters = size_bytes >> ceil_log2 (align); unsigned remainder = size_bytes & (align - 1); unsigned inc = GET_MODE_SIZE (mode); diff --git a/gcc/config/bpf/bpf.opt b/gcc/config/bpf/bpf.opt index acfddebdad7..541ebe4dfc4 100644 --- a/gcc/config/bpf/bpf.opt +++ b/gcc/config/bpf/bpf.opt @@ -108,3 +108,7 @@ Enum(asm_dialect) String(normal) Value(ASM_NORMAL) EnumValue Enum(asm_dialect) String(pseudoc) Value(ASM_PSEUDOC) + +minline-memops-threshold= +Target RejectNegative Joined UInteger Var(bpf_inline_memops_threshold) Init(1024) +-minline-memops-threshold=<number> Maximum size of memset/memmove/memcpy to inline, larger sizes will use a library call. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index c0d604a2c5c..85c938d4a14 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -971,7 +971,7 @@ Objective-C and Objective-C++ Dialects}. @gccoptlist{-mbig-endian -mlittle-endian -mframe-limit=@var{bytes} -mxbpf -mco-re -mno-co-re -mjmpext -mjmp32 -malu32 -mv3-atomics -mbswap -msdiv -msmov -mcpu=@var{version} --masm=@var{dialect}} +-masm=@var{dialect} -minline-memops-threshold=@var{bytes}} @emph{FR30 Options} @gccoptlist{-msmall-model -mno-lsim} @@ -25701,6 +25701,15 @@ Outputs pseudo-c assembly dialect. @end table +@opindex -minline-memops-threshold +@item -minline-memops-threshold=@var{bytes} +Specifies a size threshold in bytes at or below which memmove, memcpy +and memset shall always be expanded inline. Operations dealing with +sizes larger than this threshold would have to be be implemented using +a library call instead of being expanded inline, but since BPF doesn't +allow libcalls, exceeding this threshold results in a compile-time +error. The default is @samp{1024} bytes. + @end table @node FR30 Options diff --git a/gcc/testsuite/gcc.target/bpf/inline-memops-threshold-1.c b/gcc/testsuite/gcc.target/bpf/inline-memops-threshold-1.c new file mode 100644 index 00000000000..c2ba4db5b7b --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/inline-memops-threshold-1.c @@ -0,0 +1,15 @@ + +/* { dg-do compile } */ +/* { dg-options "-O2" "-minline-memops-threshold=256"} */ + +char buf[512]; + +void +mov_small (void) +{ + __builtin_memmove (buf, buf + 2, 255); +} + +/* { dg-final { scan-assembler-not "call" } } */ +/* { dg-final { scan-assembler "ldxb" } } */ +/* { dg-final { scan-assembler "stxb" } } */ diff --git a/gcc/testsuite/gcc.target/bpf/inline-memops-threshold-2.c b/gcc/testsuite/gcc.target/bpf/inline-memops-threshold-2.c new file mode 100644 index 00000000000..50910483890 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/inline-memops-threshold-2.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -minline-memops-threshold=256" } */ + +char buf[512]; + +void +mov_big (void) +{ + __builtin_memmove (buf, buf + 12, 354); /* { dg-error "too many bytes" } */ +} +