]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
bpf: add size threshold for inlining mem builtins
authorDavid Faust <david.faust@oracle.com>
Thu, 7 Mar 2024 17:29:32 +0000 (09:29 -0800)
committerDavid Faust <david.faust@oracle.com>
Fri, 8 Mar 2024 18:12:42 +0000 (10:12 -0800)
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
gcc/config/bpf/bpf.opt
gcc/doc/invoke.texi
gcc/testsuite/gcc.target/bpf/inline-memops-threshold-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/bpf/inline-memops-threshold-2.c [new file with mode: 0644]

index 0e33f4347ba605b110dca00e9c118c9f04081e97..fb60770c170a236944e1aae48317f0fa52d819ca 100644 (file)
@@ -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);
index acfddebdad718909127b1e1440f58d98944967a8..541ebe4dfc4ed7d532f34194308cf5dc4edf23a5 100644 (file)
@@ -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.
index c0d604a2c5cb5df221218c19b6f73ba113a53857..85c938d4a1486846a35a646f0af923e6124b8e0e 100644 (file)
@@ -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 (file)
index 0000000..c2ba4db
--- /dev/null
@@ -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 (file)
index 0000000..5091048
--- /dev/null
@@ -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" } */
+}
+