https://gcc.gnu.org/g:548dbf6f87878800f214982e6c6d104b8a2a6ea1
commit 548dbf6f87878800f214982e6c6d104b8a2a6ea1 Author: David Faust <david.fa...@oracle.com> Date: Mon Mar 4 09:35:01 2024 -0800 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. (cherry picked from commit eae6b63b5b5426f943f58b5ae0bf0a6068ca8ad6) Diff: --- gcc/config/bpf/bpf-protos.h | 1 + gcc/config/bpf/bpf.cc | 66 +++++++++++++++++++++++++++++++++ gcc/config/bpf/bpf.md | 17 +++++++++ gcc/testsuite/gcc.target/bpf/memset-1.c | 39 +++++++++++++++++++ 4 files changed, 123 insertions(+) diff --git a/gcc/config/bpf/bpf-protos.h b/gcc/config/bpf/bpf-protos.h index 3b63b18857c..876569ab645 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 233025aac95..c008a961e51 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 c467bff85b7..1b3cc5c9f6f 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 00000000000..9e9f8eff028 --- /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 } } */