[llvm-branch-commits] [llvm] 761b913 - [BPF] treat compiler fence as codegen no-op (#196734)

Douglas Yung via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jun 10 10:47:01 PDT 2026


Author: Bidhan
Date: 2026-06-10T17:46:45Z
New Revision: 761b9134dd9beda6f133fdc19a42b148834cb06b

URL: https://github.com/llvm/llvm-project/commit/761b9134dd9beda6f133fdc19a42b148834cb06b
DIFF: https://github.com/llvm/llvm-project/commit/761b9134dd9beda6f133fdc19a42b148834cb06b.diff

LOG: [BPF] treat compiler fence as codegen no-op (#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 single-thread (compiler) fences to `ISD::MEMBARRIER`
(no-op) and produces an error for cross-thread (runtime) fences.

Added: 
    llvm/test/CodeGen/BPF/fence-singlethread.ll

Modified: 
    llvm/lib/Target/BPF/BPFISelLowering.cpp
    llvm/lib/Target/BPF/BPFISelLowering.h

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/BPF/BPFISelLowering.cpp b/llvm/lib/Target/BPF/BPFISelLowering.cpp
index 5c03776dd6653..faf3af0918d54 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;
@@ -368,6 +370,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);
   }
@@ -772,6 +776,19 @@ SDValue BPFTargetLowering::LowerATOMIC_LOAD_STORE(SDValue Op,
   return Op;
 }
 
+SDValue BPFTargetLowering::LowerATOMIC_FENCE(SDValue Op,
+                                             SelectionDAG &DAG) const {
+  SDLoc DL(Op);
+  SyncScope::ID FenceSSID =
+      static_cast<SyncScope::ID>(Op.getConstantOperandVal(2));
+
+  if (FenceSSID == SyncScope::SingleThread)
+    // MEMBARRIER is a compiler barrier; it codegens to a no-op.
+    return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
+
+  report_fatal_error("Runtime fence is not supported at the moment");
+}
+
 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 8607e4f8c9e69..df1e2d8114ae1 100644
--- a/llvm/lib/Target/BPF/BPFISelLowering.h
+++ b/llvm/lib/Target/BPF/BPFISelLowering.h
@@ -73,6 +73,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/fence-singlethread.ll b/llvm/test/CodeGen/BPF/fence-singlethread.ll
new file mode 100644
index 0000000000000..91ea38db8b8c8
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/fence-singlethread.ll
@@ -0,0 +1,14 @@
+; RUN: llc < %s -mtriple=bpfel | FileCheck %s
+; RUN: llc < %s -mtriple=bpfeb | FileCheck %s
+
+; CHECK-LABEL: fence_singlethread:
+; CHECK-COUNT-4: #MEMBARRIER
+; CHECK-NEXT:    exit
+define void @fence_singlethread() nounwind {
+entry:
+  fence syncscope("singlethread") acquire
+  fence syncscope("singlethread") release
+  fence syncscope("singlethread") acq_rel
+  fence syncscope("singlethread") seq_cst
+  ret void
+}


        


More information about the llvm-branch-commits mailing list