aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Faust <david.faust@oracle.com>2024-03-04 09:35:01 -0800
committerDavid Faust <david.faust@oracle.com>2024-03-04 11:48:18 -0800
commiteae6b63b5b5426f943f58b5ae0bf0a6068ca8ad6 (patch)
tree83c54d59af77c09a07b8161ca1c386850e5cf02a
parentaadb311c1a3712a1360a252ae21cf7f375959b5c (diff)
downloadgcc-eae6b63b5b5426f943f58b5ae0bf0a6068ca8ad6.zip
gcc-eae6b63b5b5426f943f58b5ae0bf0a6068ca8ad6.tar.gz
gcc-eae6b63b5b5426f943f58b5ae0bf0a6068ca8ad6.tar.bz2
bpf: add inline memset expansion
Similar to memmove and memcpy, the BPF backend cannot fall back on a library call to implement __builtin_memset, and should always expand calls to it inline if possible. This patch implements simple inline expansion of memset in the BPF backend in a verifier-friendly way. Similar to memcpy and memmove, the size must be an integer constant, as is also required by clang. gcc/ * config/bpf/bpf-protos.h (bpf_expand_setmem): New prototype. * config/bpf/bpf.cc (bpf_expand_setmem): New. * config/bpf/bpf.md (setmemdi): New define_expand. gcc/testsuite/ * gcc.target/bpf/memset-1.c: New test.
-rw-r--r--gcc/config/bpf/bpf-protos.h1
-rw-r--r--gcc/config/bpf/bpf.cc66
-rw-r--r--gcc/config/bpf/bpf.md17
-rw-r--r--gcc/testsuite/gcc.target/bpf/memset-1.c39
4 files changed, 123 insertions, 0 deletions
diff --git a/gcc/config/bpf/bpf-protos.h b/gcc/config/bpf/bpf-protos.h
index 366acb8..ac0c2f4 100644
--- a/gcc/config/bpf/bpf-protos.h
+++ b/gcc/config/bpf/bpf-protos.h
@@ -36,5 +36,6 @@ class gimple_opt_pass;
gimple_opt_pass *make_pass_lower_bpf_core (gcc::context *ctxt);
bool bpf_expand_cpymem (rtx *, bool);
+bool bpf_expand_setmem (rtx *);
#endif /* ! GCC_BPF_PROTOS_H */
diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
index 22b0cf2..0e33f43 100644
--- a/gcc/config/bpf/bpf.cc
+++ b/gcc/config/bpf/bpf.cc
@@ -1309,6 +1309,72 @@ bpf_expand_cpymem (rtx *operands, bool is_move)
return true;
}
+/* Expand setmem, as from __builtin_memset.
+ OPERANDS are the same as the setmem pattern.
+ Return true if the expansion was successful, false otherwise. */
+
+bool
+bpf_expand_setmem (rtx *operands)
+{
+ /* Size must be constant for this expansion to work. */
+ if (!CONST_INT_P (operands[1]))
+ {
+ if (flag_building_libgcc)
+ warning (0, "could not inline call to %<__builtin_memset%>: "
+ "size must be constant");
+ else
+ error ("could not inline call to %<__builtin_memset%>: "
+ "size must be constant");
+ return false;
+ }
+
+ /* Alignment is a CONST_INT. */
+ gcc_assert (CONST_INT_P (operands[3]));
+
+ rtx dst = operands[0];
+ rtx size = operands[1];
+ rtx val = operands[2];
+ unsigned HOST_WIDE_INT size_bytes = UINTVAL (size);
+ unsigned align = UINTVAL (operands[3]);
+ enum machine_mode mode;
+ switch (align)
+ {
+ case 1: mode = QImode; break;
+ case 2: mode = HImode; break;
+ case 4: mode = SImode; break;
+ case 8: mode = DImode; break;
+ default:
+ gcc_unreachable ();
+ }
+
+ unsigned iters = size_bytes >> ceil_log2 (align);
+ unsigned remainder = size_bytes & (align - 1);
+ unsigned inc = GET_MODE_SIZE (mode);
+ unsigned offset = 0;
+
+ for (unsigned int i = 0; i < iters; i++)
+ {
+ emit_move_insn (adjust_address (dst, mode, offset), val);
+ offset += inc;
+ }
+ if (remainder & 4)
+ {
+ emit_move_insn (adjust_address (dst, SImode, offset), val);
+ offset += 4;
+ remainder -= 4;
+ }
+ if (remainder & 2)
+ {
+ emit_move_insn (adjust_address (dst, HImode, offset), val);
+ offset += 2;
+ remainder -= 2;
+ }
+ if (remainder & 1)
+ emit_move_insn (adjust_address (dst, QImode, offset), val);
+
+ return true;
+}
+
/* Finally, build the GCC target. */
struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/bpf/bpf.md b/gcc/config/bpf/bpf.md
index ca677bc..ea688aa 100644
--- a/gcc/config/bpf/bpf.md
+++ b/gcc/config/bpf/bpf.md
@@ -663,4 +663,21 @@
FAIL;
})
+;; memset
+;; 0 is dst
+;; 1 is length
+;; 2 is value
+;; 3 is alignment
+(define_expand "setmemdi"
+ [(set (match_operand:BLK 0 "memory_operand")
+ (match_operand:QI 2 "nonmemory_operand"))
+ (use (match_operand:DI 1 "general_operand"))
+ (match_operand 3 "immediate_operand")]
+ ""
+ {
+ if (bpf_expand_setmem (operands))
+ DONE;
+ FAIL;
+})
+
(include "atomic.md")
diff --git a/gcc/testsuite/gcc.target/bpf/memset-1.c b/gcc/testsuite/gcc.target/bpf/memset-1.c
new file mode 100644
index 0000000..9e9f8ef
--- /dev/null
+++ b/gcc/testsuite/gcc.target/bpf/memset-1.c
@@ -0,0 +1,39 @@
+/* Ensure memset is expanded inline rather than emitting a libcall. */
+
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+struct context {
+ unsigned int data;
+ unsigned int data_end;
+ unsigned int data_meta;
+ unsigned int ingress;
+ unsigned int queue_index;
+ unsigned int egress;
+};
+
+void
+set_small (struct context *ctx)
+{
+ void *data = (void *)(long)ctx->data;
+ char *dest = data;
+ __builtin_memset (dest + 4, 0, sizeof (struct context) - 4);
+}
+
+void
+set_large (struct context *ctx)
+{
+ void *data = (void *)(long)ctx->data;
+ char *dest = data;
+ __builtin_memset (dest, 0xfe, 130);
+}
+
+void
+set_variable (struct context *ctx)
+{
+ void *data = (void *)(long)ctx->data;
+ char *dest = data;
+ __builtin_memset (dest, 0xbc, ctx->data_meta); /* { dg-error "could not inline call" } */
+}
+
+/* { dg-final { scan-assembler-times "call" 0 } } */