[llvm] [BPF] treat compiler fence as codegen no-op (PR #196734)

via llvm-commits llvm-commits at lists.llvm.org
Sat May 9 08:48:48 PDT 2026


https://github.com/bidhan-a created https://github.com/llvm/llvm-project/pull/196734

The BPF backend has no instruction-selection pattern for `ISD::ATOMIC_FENCE`, so LLVM IR containing a fence instruction crashes with `Cannot select: AtomicFence...`.

**Rust code snippet**

```
#[unsafe(no_mangle)]
pub fn entrypoint(_input: *mut u8) -> u64 {
    core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
    0
}
```

**LLVM IR**

```
; ModuleID = 'linked_module'
source_filename = "linked_module"
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "bpfel"

; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
define dso_local noundef i64 @entrypoint(ptr noundef readnone captures(none) %0) unnamed_addr #0 {
  fence syncscope("singlethread") seq_cst
  ret i64 0
}

attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn "target-cpu"="generic" }

!llvm.ident = !{!0}

!0 = !{!"rustc version 1.97.0-nightly (f53b654a8 2026-04-30)"}
```

**Error**

```
LLVM ERROR: Cannot select: 0x7fcf7701a1c0: ch = AtomicFence 0x7fcf75718df8, TargetConstant:i64<7>, TargetConstant:i64<0>
In function: entrypoint

Stack dump:
          0.    Running pass 'Function Pass Manager' on module 'linked_module'.
          1.    Running pass 'BPF DAG->DAG Pattern Instruction Selection' on function '@entrypoint'
```

-----

**Fix**

This patch lowers `ATOMIC_FENCE` to `ISD::MEMBARRIER`, which acts as a compiler barrier and codegens to a no-op, following the pattern used by other backends (e.g. [XCore](https://github.com/blueshift-gg/llvm-project/blob/BPF_atomic_fence/llvm/lib/Target/XCore/XCoreISelLowering.cpp#L885)).

>From ff7569d31c87432f8c949e769ed004c4c26f8218 Mon Sep 17 00:00:00 2001
From: bidhan-a <bidhan619 at gmail.com>
Date: Fri, 8 May 2026 13:20:22 +0545
Subject: [PATCH] [BPF] treat compiler fence as codegen no-op

---
 llvm/lib/Target/BPF/BPFISelLowering.cpp | 12 ++++++++++++
 llvm/lib/Target/BPF/BPFISelLowering.h   |  1 +
 llvm/test/CodeGen/BPF/atomic-fence.ll   | 19 +++++++++++++++++++
 3 files changed, 32 insertions(+)
 create mode 100644 llvm/test/CodeGen/BPF/atomic-fence.ll

diff --git a/llvm/lib/Target/BPF/BPFISelLowering.cpp b/llvm/lib/Target/BPF/BPFISelLowering.cpp
index 6ffa9d1693bc0..2fe934c814b88 100644
--- a/llvm/lib/Target/BPF/BPFISelLowering.cpp
+++ b/llvm/lib/Target/BPF/BPFISelLowering.cpp
@@ -110,6 +110,8 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM,
     setOperationAction(ISD::ATOMIC_STORE, VT, Custom);
   }
 
+  setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom);
+
   for (auto VT : { MVT::i32, MVT::i64 }) {
     if (VT == MVT::i32 && !STI.getHasAlu32())
       continue;
@@ -372,6 +374,8 @@ SDValue BPFTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
   case ISD::ATOMIC_LOAD:
   case ISD::ATOMIC_STORE:
     return LowerATOMIC_LOAD_STORE(Op, DAG);
+  case ISD::ATOMIC_FENCE:
+    return LowerATOMIC_FENCE(Op, DAG);
   case ISD::TRAP:
     return LowerTRAP(Op, DAG);
   }
@@ -770,6 +774,14 @@ SDValue BPFTargetLowering::LowerATOMIC_LOAD_STORE(SDValue Op,
   return Op;
 }
 
+SDValue BPFTargetLowering::LowerATOMIC_FENCE(SDValue Op,
+                                             SelectionDAG &DAG) const {
+  SDLoc DL(Op);
+
+  // MEMBARRIER is a compiler barrier; it codegens to a no-op.
+  return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
+}
+
 static Function *createBPFUnreachable(Module *M) {
   if (auto *Fn = M->getFunction(BPF_TRAP))
     return Fn;
diff --git a/llvm/lib/Target/BPF/BPFISelLowering.h b/llvm/lib/Target/BPF/BPFISelLowering.h
index b16fce0dd418f..9bcc5157c0646 100644
--- a/llvm/lib/Target/BPF/BPFISelLowering.h
+++ b/llvm/lib/Target/BPF/BPFISelLowering.h
@@ -82,6 +82,7 @@ class BPFTargetLowering : public TargetLowering {
   SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerATOMIC_LOAD_STORE(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerTRAP(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/test/CodeGen/BPF/atomic-fence.ll b/llvm/test/CodeGen/BPF/atomic-fence.ll
new file mode 100644
index 0000000000000..7c9d10305ef2c
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/atomic-fence.ll
@@ -0,0 +1,19 @@
+; RUN: llc < %s -mtriple=bpfel | FileCheck %s
+; RUN: llc < %s -mtriple=bpfeb | FileCheck %s
+
+; CHECK-LABEL: atomic_fence
+; CHECK: #MEMBARRIER
+; CHECK: #MEMBARRIER
+; CHECK: #MEMBARRIER
+; CHECK: #MEMBARRIER
+; CHECK: #MEMBARRIER
+; CHECK: exit
+define void @atomic_fence() nounwind {
+entry:
+  fence acquire
+  fence release
+  fence acq_rel
+  fence seq_cst
+  fence syncscope("singlethread") seq_cst
+  ret void
+}



More information about the llvm-commits mailing list