[llvm] [BPF] Allow libcalls behind a feature gate (PR #168442)
Lucas Ste via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 19 06:23:25 PST 2025
https://github.com/LucasSte updated https://github.com/llvm/llvm-project/pull/168442
>From a1e74bf8a927532308862232a4d25e426774b558 Mon Sep 17 00:00:00 2001
From: Lucas <lucas.tnagel at gmail.com>
Date: Mon, 17 Nov 2025 17:53:09 -0300
Subject: [PATCH] [BPF] Allow libcalls in BPF programs
---
llvm/lib/Target/BPF/BPF.td | 4 +++
llvm/lib/Target/BPF/BPFISelLowering.cpp | 23 ++++++++++++--
llvm/lib/Target/BPF/BPFISelLowering.h | 10 ++++++
llvm/lib/Target/BPF/BPFSubtarget.cpp | 1 +
llvm/lib/Target/BPF/BPFSubtarget.h | 3 ++
llvm/test/CodeGen/BPF/atomic-oversize.ll | 2 --
llvm/test/CodeGen/BPF/builtin_calls.ll | 39 ++++++++++++++++++++++++
llvm/test/CodeGen/BPF/struct_ret2.ll | 2 +-
8 files changed, 78 insertions(+), 6 deletions(-)
create mode 100644 llvm/test/CodeGen/BPF/builtin_calls.ll
diff --git a/llvm/lib/Target/BPF/BPF.td b/llvm/lib/Target/BPF/BPF.td
index a7aa6274f5ac1..436b7eef600e7 100644
--- a/llvm/lib/Target/BPF/BPF.td
+++ b/llvm/lib/Target/BPF/BPF.td
@@ -31,6 +31,10 @@ def MisalignedMemAccess : SubtargetFeature<"allows-misaligned-mem-access",
"AllowsMisalignedMemAccess", "true",
"Allows misaligned memory access">;
+def AllowBuiltinCall : SubtargetFeature<"allow-builtin-calls",
+ "AllowBuiltinCalls", "true",
+ "Allow calls to builtin functions">;
+
def : Proc<"generic", []>;
def : Proc<"v1", []>;
def : Proc<"v2", []>;
diff --git a/llvm/lib/Target/BPF/BPFISelLowering.cpp b/llvm/lib/Target/BPF/BPFISelLowering.cpp
index ecefd2379356a..c9df0c9b627e9 100644
--- a/llvm/lib/Target/BPF/BPFISelLowering.cpp
+++ b/llvm/lib/Target/BPF/BPFISelLowering.cpp
@@ -208,6 +208,7 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM,
HasMovsx = STI.hasMovsx();
AllowsMisalignedMemAccess = STI.getAllowsMisalignedMemAccess();
+ AllowBuiltinCalls = STI.getAllowBuiltinCalls();
}
bool BPFTargetLowering::allowsMisalignedMemoryAccesses(EVT VT, unsigned, Align,
@@ -567,9 +568,10 @@ SDValue BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
} else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) {
if (StringRef(E->getSymbol()) != BPF_TRAP) {
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT, 0);
- fail(CLI.DL, DAG,
- Twine("A call to built-in function '" + StringRef(E->getSymbol()) +
- "' is not supported."));
+ if (!AllowBuiltinCalls)
+ fail(CLI.DL, DAG,
+ Twine("A call to built-in function '" + StringRef(E->getSymbol()) +
+ "' is not supported."));
}
}
@@ -1196,3 +1198,18 @@ bool BPFTargetLowering::isLegalAddressingMode(const DataLayout &DL,
return true;
}
+
+bool BPFTargetLowering::shouldSignExtendTypeInLibCall(Type *Ty,
+ bool IsSigned) const {
+ return IsSigned || Ty->isIntegerTy(32);
+}
+
+bool BPFTargetLowering::CanLowerReturn(
+ CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context,
+ const Type *RetTy) const {
+ // At minimal return Outs.size() <= 1, or check valid types in CC.
+ SmallVector<CCValAssign, 16> RVLocs;
+ CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
+ return CCInfo.CheckReturn(Outs, getHasAlu32() ? RetCC_BPF32 : RetCC_BPF64);
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/BPF/BPFISelLowering.h b/llvm/lib/Target/BPF/BPFISelLowering.h
index 8607e4f8c9e69..a283859fa29c1 100644
--- a/llvm/lib/Target/BPF/BPFISelLowering.h
+++ b/llvm/lib/Target/BPF/BPFISelLowering.h
@@ -68,6 +68,8 @@ class BPFTargetLowering : public TargetLowering {
// Allows Misalignment
bool AllowsMisalignedMemAccess;
+ bool AllowBuiltinCalls;
+
SDValue LowerSDIVSREM(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
@@ -163,6 +165,14 @@ class BPFTargetLowering : public TargetLowering {
MachineBasicBlock *
EmitInstrWithCustomInserterLDimm64(MachineInstr &MI,
MachineBasicBlock *BB) const;
+
+ /// Returns true if arguments should be sign-extended in lib calls.
+ bool shouldSignExtendTypeInLibCall(Type *Ty, bool IsSigned) const override;
+
+ bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF,
+ bool IsVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ LLVMContext &Context, const Type *RetTy) const override;
};
}
diff --git a/llvm/lib/Target/BPF/BPFSubtarget.cpp b/llvm/lib/Target/BPF/BPFSubtarget.cpp
index 726f8f4b39827..77a1a5fe7444c 100644
--- a/llvm/lib/Target/BPF/BPFSubtarget.cpp
+++ b/llvm/lib/Target/BPF/BPFSubtarget.cpp
@@ -70,6 +70,7 @@ void BPFSubtarget::initializeEnvironment() {
HasLoadAcqStoreRel = false;
HasGotox = false;
AllowsMisalignedMemAccess = false;
+ AllowBuiltinCalls = false;
}
void BPFSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
diff --git a/llvm/lib/Target/BPF/BPFSubtarget.h b/llvm/lib/Target/BPF/BPFSubtarget.h
index 24eff862224b0..40751fc9b7454 100644
--- a/llvm/lib/Target/BPF/BPFSubtarget.h
+++ b/llvm/lib/Target/BPF/BPFSubtarget.h
@@ -70,6 +70,8 @@ class BPFSubtarget : public BPFGenSubtargetInfo {
bool HasLdsx, HasMovsx, HasBswap, HasSdivSmod, HasGotol, HasStoreImm,
HasLoadAcqStoreRel, HasGotox;
+ bool AllowBuiltinCalls;
+
std::unique_ptr<CallLowering> CallLoweringInfo;
std::unique_ptr<InstructionSelector> InstSelector;
std::unique_ptr<LegalizerInfo> Legalizer;
@@ -101,6 +103,7 @@ class BPFSubtarget : public BPFGenSubtargetInfo {
bool hasStoreImm() const { return HasStoreImm; }
bool hasLoadAcqStoreRel() const { return HasLoadAcqStoreRel; }
bool hasGotox() const { return HasGotox; }
+ bool getAllowBuiltinCalls() const { return AllowBuiltinCalls; }
bool isLittleEndian() const { return IsLittleEndian; }
diff --git a/llvm/test/CodeGen/BPF/atomic-oversize.ll b/llvm/test/CodeGen/BPF/atomic-oversize.ll
index 187f0964d4fb8..6dc49398f091d 100644
--- a/llvm/test/CodeGen/BPF/atomic-oversize.ll
+++ b/llvm/test/CodeGen/BPF/atomic-oversize.ll
@@ -1,6 +1,4 @@
; RUN: llc -mtriple=bpf < %s | FileCheck %s
-; XFAIL: *
-; Doesn't currently build, with error 'only small returns supported'.
define void @test(ptr %a) nounwind {
; CHECK-LABEL: test:
diff --git a/llvm/test/CodeGen/BPF/builtin_calls.ll b/llvm/test/CodeGen/BPF/builtin_calls.ll
new file mode 100644
index 0000000000000..18199eba7222a
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/builtin_calls.ll
@@ -0,0 +1,39 @@
+; RUN: llc -march=bpfel -mattr=+allow-builtin-calls < %s | FileCheck %s
+;
+; C code for this test case:
+;
+; long func(long a, long b) {
+; long x;
+; return __builtin_mul_overflow(a, b, &x);
+; }
+
+
+declare { i64, i1 } @llvm.smul.with.overflow.i64(i64, i64)
+
+define noundef range(i64 0, 2) i64 @func(i64 noundef %a, i64 noundef %b) local_unnamed_addr {
+entry:
+ %0 = tail call { i64, i1 } @llvm.smul.with.overflow.i64(i64 %a, i64 %b)
+ %1 = extractvalue { i64, i1 } %0, 1
+ %conv = zext i1 %1 to i64
+ ret i64 %conv
+}
+
+; CHECK-LABEL: func
+; CHECK: r4 = r2
+; CHECK: r2 = r1
+; CHECK: r3 = r2
+; CHECK: r3 s>>= 63
+; CHECK: r5 = r4
+; CHECK: r5 s>>= 63
+; CHECK: r1 = r10
+; CHECK: r1 += -16
+; CHECK: call __multi3
+; CHECK: r1 = *(u64 *)(r10 - 16)
+; CHECK: r1 s>>= 63
+; CHECK: w0 = 1
+; CHECK: r2 = *(u64 *)(r10 - 8)
+; CHECK: if r2 != r1 goto LBB0_2
+; CHECK: # %bb.1: # %entry
+; CHECK: w0 = 0
+; CHECK: LBB0_2: # %entry
+; CHECK: exit
\ No newline at end of file
diff --git a/llvm/test/CodeGen/BPF/struct_ret2.ll b/llvm/test/CodeGen/BPF/struct_ret2.ll
index 170d55cc29df0..c7aa7f58c9597 100644
--- a/llvm/test/CodeGen/BPF/struct_ret2.ll
+++ b/llvm/test/CodeGen/BPF/struct_ret2.ll
@@ -1,6 +1,6 @@
; RUN: not llc -mtriple=bpf < %s 2> %t1
; RUN: FileCheck %s < %t1
-; CHECK: only small returns
+; CHECK: aggregate returns are not supported
; Function Attrs: nounwind uwtable
define { i64, i32 } @foo(i32 %a, i32 %b, i32 %c) #0 {
More information about the llvm-commits
mailing list