[llvm] [BPF] crash fix for memcpy with unsupported alignment (PR #199541)

Claire Fan via llvm-commits llvm-commits at lists.llvm.org
Mon May 25 09:21:25 PDT 2026


https://github.com/clairechingching updated https://github.com/llvm/llvm-project/pull/199541

>From 4c5139ed13aa9f30a4720f62a9c24a27f2f03d90 Mon Sep 17 00:00:00 2001
From: Claire Fan <fanyungching at gmail.com>
Date: Mon, 25 May 2026 12:21:11 -0400
Subject: [PATCH] [BPF] crash fix for memcpy with unsupported alignment

---
 llvm/lib/Target/BPF/BPFSelectionDAGInfo.cpp   | 13 +++++++++
 llvm/lib/Target/BPF/BPFSelectionDAGInfo.h     |  2 +-
 .../CodeGen/BPF/libcall-memcpy-threshold.ll   | 28 +++++++++++++++++++
 3 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/BPF/libcall-memcpy-threshold.ll

diff --git a/llvm/lib/Target/BPF/BPFSelectionDAGInfo.cpp b/llvm/lib/Target/BPF/BPFSelectionDAGInfo.cpp
index 0e6d35dd3781f..ba93c868c2c8b 100644
--- a/llvm/lib/Target/BPF/BPFSelectionDAGInfo.cpp
+++ b/llvm/lib/Target/BPF/BPFSelectionDAGInfo.cpp
@@ -21,9 +21,18 @@ using namespace llvm;
 
 #define DEBUG_TYPE "bpf-selectiondag-info"
 
+static cl::opt<unsigned> BPFMaxStoresPerMemFunc(
+    "bpf-max-stores-per-memfunc", cl::Hidden, cl::init(128),
+    cl::desc("Set the maximum number of stores for inlined BPF memory "
+             "intrinsics"));
+
 BPFSelectionDAGInfo::BPFSelectionDAGInfo()
     : SelectionDAGGenTargetInfo(BPFGenSDNodeInfo) {}
 
+unsigned BPFSelectionDAGInfo::getCommonMaxStoresPerMemFunc() const {
+  return BPFMaxStoresPerMemFunc;
+}
+
 SDValue BPFSelectionDAGInfo::EmitTargetCodeForMemcpy(
     SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
     SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
@@ -33,6 +42,10 @@ SDValue BPFSelectionDAGInfo::EmitTargetCodeForMemcpy(
   if (!ConstantSize)
     return SDValue();
 
+  // BPF::MEMCPY supports alignment up to 8 bytes.
+  if (Alignment.value() > 8)
+    return SDValue();
+
   unsigned CopyLen = ConstantSize->getZExtValue();
   unsigned StoresNumEstimate = alignTo(CopyLen, Alignment) >> Log2(Alignment);
   // Impose the same copy length limit as MaxStoresPerMemcpy.
diff --git a/llvm/lib/Target/BPF/BPFSelectionDAGInfo.h b/llvm/lib/Target/BPF/BPFSelectionDAGInfo.h
index 7345d2d7e4738..eebea78435d16 100644
--- a/llvm/lib/Target/BPF/BPFSelectionDAGInfo.h
+++ b/llvm/lib/Target/BPF/BPFSelectionDAGInfo.h
@@ -31,7 +31,7 @@ class BPFSelectionDAGInfo : public SelectionDAGGenTargetInfo {
                                   MachinePointerInfo DstPtrInfo,
                                   MachinePointerInfo SrcPtrInfo) const override;
 
-  unsigned getCommonMaxStoresPerMemFunc() const { return 128; }
+  unsigned getCommonMaxStoresPerMemFunc() const;
 };
 
 } // namespace llvm
diff --git a/llvm/test/CodeGen/BPF/libcall-memcpy-threshold.ll b/llvm/test/CodeGen/BPF/libcall-memcpy-threshold.ll
new file mode 100644
index 0000000000000..49f8c12d0d5e1
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/libcall-memcpy-threshold.ll
@@ -0,0 +1,28 @@
+; RUN: llc < %s -mtriple=bpfel -verify-machineinstrs -bpf-max-stores-per-memfunc=1 | FileCheck %s --check-prefix=LIBCALL
+
+; StoresNumEstimate = alignTo(16, 8) >> 3 = 2, which is greater than the
+; getCommonMaxStoresPerMemFunc() value of 1 from -bpf-max-stores-per-memfunc.
+; That prevents inline expansion and lets the generic memcpy libcall path fire.
+define dso_local void @small_copy(ptr nocapture %dst, ptr nocapture readonly %src) local_unnamed_addr {
+entry:
+  tail call void @llvm.memcpy.p0.p0.i64(ptr align 8 %dst, ptr align 8 %src, i64 16, i1 false)
+  ret void
+}
+
+; StoresNumEstimate = alignTo(16, 16) >> 4 = 1, so the threshold still allows
+; inline expansion here. The memcpy must still avoid BPF::MEMCPY because BPF
+; only supports alignment up to 8 bytes.
+define dso_local void @align16_copy(ptr nocapture %dst, ptr nocapture readonly %src) local_unnamed_addr {
+entry:
+  tail call void @llvm.memcpy.p0.p0.i64(ptr align 16 %dst, ptr align 16 %src, i64 16, i1 false)
+  ret void
+}
+
+declare void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1 immarg)
+
+; LIBCALL-LABEL: small_copy:
+; LIBCALL:       r3 = 16
+; LIBCALL:       call memcpy
+; LIBCALL-LABEL: align16_copy:
+; LIBCALL:       r3 = 16
+; LIBCALL:       call memcpy



More information about the llvm-commits mailing list