https://github.com/clairechingching created
https://github.com/llvm/llvm-project/pull/180394
This patch adds i128 return type support for BPF targets through direct return
using registers R0/R1. It also extends support to small aggregate return types
that can fit within two 64-bit registers, such as structs or arrays with a
total size ≤ 128 bits and fewer than two elements
**Test Updates**
`atomic-oversize.ll`: i128 return type now supported
`struct_ret2.ll`: {i64, i32} return type now supported
`struct_ret1.ll`: bar function with {i64, i32} return type is now supported;
large struct return remains unsupported and still correctly triggers the
“aggregate return unsupported” error
**New Tests**
`i128-bpf64.ll`: Verifies i128 return under RetCC_BPF64
`struct_ret3.ll` / `struct_ret4.ll`: {i32, i32, i32} and {i64, i32, i32} (more
than 3 elements) returns remain unsupported
`arr_ret1.ll` / `arr_ret2.ll`: Tests array-type returns
>From 86eaded7f3fc667662b29a41937e8975b1b614f1 Mon Sep 17 00:00:00 2001
From: Claire Fan <[email protected]>
Date: Sun, 8 Feb 2026 09:07:52 +0100
Subject: [PATCH] i128 direct return support
---
llvm/lib/Target/BPF/BPFCallingConv.td | 6 ++++--
llvm/lib/Target/BPF/BPFISelLowering.cpp | 27 +++++++++++++++++-------
llvm/test/CodeGen/BPF/arr_ret1.ll | 13 ++++++++++++
llvm/test/CodeGen/BPF/arr_ret2.ll | 12 +++++++++++
llvm/test/CodeGen/BPF/atomic-oversize.ll | 12 +++++++----
llvm/test/CodeGen/BPF/i128-bpf64.ll | 16 ++++++++++++++
llvm/test/CodeGen/BPF/struct_ret1.ll | 1 -
llvm/test/CodeGen/BPF/struct_ret2.ll | 7 +++---
llvm/test/CodeGen/BPF/struct_ret3.ll | 12 +++++++++++
llvm/test/CodeGen/BPF/struct_ret4.ll | 12 +++++++++++
10 files changed, 100 insertions(+), 18 deletions(-)
create mode 100644 llvm/test/CodeGen/BPF/arr_ret1.ll
create mode 100644 llvm/test/CodeGen/BPF/arr_ret2.ll
create mode 100644 llvm/test/CodeGen/BPF/i128-bpf64.ll
create mode 100644 llvm/test/CodeGen/BPF/struct_ret3.ll
create mode 100644 llvm/test/CodeGen/BPF/struct_ret4.ll
diff --git a/llvm/lib/Target/BPF/BPFCallingConv.td
b/llvm/lib/Target/BPF/BPFCallingConv.td
index a557211437e95..d92cc959bdeb6 100644
--- a/llvm/lib/Target/BPF/BPFCallingConv.td
+++ b/llvm/lib/Target/BPF/BPFCallingConv.td
@@ -11,7 +11,7 @@
//===----------------------------------------------------------------------===//
// BPF 64-bit C return-value convention.
-def RetCC_BPF64 : CallingConv<[CCIfType<[i64], CCAssignToReg<[R0]>>]>;
+def RetCC_BPF64 : CallingConv<[CCIfType<[i64], CCAssignToReg<[R0, R1]>>]>;
// BPF 64-bit C Calling convention.
def CC_BPF64 : CallingConv<[
@@ -28,7 +28,9 @@ def CC_BPF64 : CallingConv<[
// Return-value convention when -mattr=+alu32 enabled
def RetCC_BPF32 : CallingConv<[
CCIfType<[i32], CCAssignToRegWithShadow<[W0], [R0]>>,
- CCIfType<[i64], CCAssignToRegWithShadow<[R0], [W0]>>
+ CCIfType<[i32], CCAssignToRegWithShadow<[W1], [R1]>>,
+ CCIfType<[i64], CCAssignToRegWithShadow<[R0], [W0]>>,
+ CCIfType<[i64], CCAssignToRegWithShadow<[R1], [W1]>>,
]>;
// Calling convention when -mattr=+alu32 enabled
diff --git a/llvm/lib/Target/BPF/BPFISelLowering.cpp
b/llvm/lib/Target/BPF/BPFISelLowering.cpp
index 5c03776dd6653..e4e826df97562 100644
--- a/llvm/lib/Target/BPF/BPFISelLowering.cpp
+++ b/llvm/lib/Target/BPF/BPFISelLowering.cpp
@@ -629,15 +629,24 @@ BPFTargetLowering::LowerReturn(SDValue Chain,
CallingConv::ID CallConv,
// CCValAssign - represent the assignment of the return value to a location
SmallVector<CCValAssign, 16> RVLocs;
MachineFunction &MF = DAG.getMachineFunction();
+ const Function &F = MF.getFunction();
+ Type *retTy = F.getReturnType();
+
+ if (retTy->isAggregateType()) {
+ // BPF calling convention does not allow large return that is
+ // 1. larger than 128 bit, or
+ // 2. struct/array taking up more than 2 registers
+ const DataLayout &data = F.getParent()->getDataLayout();
+ const auto *AT = dyn_cast<const ArrayType>(retTy);
+ if (Outs.size() > 2 || data.getTypeAllocSize(retTy) > 128 || (AT &&
AT->getArrayNumElements() > 2)) {
+ fail(DL, DAG, "aggregate returns are not supported");
+ return DAG.getNode(Opc, DL, MVT::Other, Chain);
+ }
+ }
// CCState - Info about the registers and stack slot.
CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
-
- if (MF.getFunction().getReturnType()->isAggregateType()) {
- fail(DL, DAG, "aggregate returns are not supported");
- return DAG.getNode(Opc, DL, MVT::Other, Chain);
- }
-
+
// Analize return values.
CCInfo.AnalyzeReturn(Outs, getHasAlu32() ? RetCC_BPF32 : RetCC_BPF64);
@@ -677,11 +686,13 @@ SDValue BPFTargetLowering::LowerCallResult(
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
- if (Ins.size() > 1) {
+ // BPF calling convention does not allow returning more than 2 registers
+ if (Ins.size() > 2) {
fail(DL, DAG, "only small returns supported");
for (auto &In : Ins)
InVals.push_back(DAG.getConstant(0, DL, In.VT));
- return DAG.getCopyFromReg(Chain, DL, 1, Ins[0].VT, InGlue).getValue(1);
+ // create a dummy node with i64 type to continue code gen
+ return DAG.getCopyFromReg(Chain, DL, 1, MVT::i64, InGlue).getValue(1);
}
CCInfo.AnalyzeCallResult(Ins, getHasAlu32() ? RetCC_BPF32 : RetCC_BPF64);
diff --git a/llvm/test/CodeGen/BPF/arr_ret1.ll
b/llvm/test/CodeGen/BPF/arr_ret1.ll
new file mode 100644
index 0000000000000..fb6e0cf0fb3b1
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/arr_ret1.ll
@@ -0,0 +1,13 @@
+; RUN: llc -mtriple=bpf < %s | FileCheck %s
+
+; Function Attrs: nounwind uwtable
+define [2 x i64] @foo(i32 %a, i32 %b, i32 %c) #0 {
+; CHECK-LABEL: foo:
+; CHECK: w4 = 1
+; CHECK-NEXT: w5 = 2
+entry:
+ %call = tail call [2 x i64] @bar(i32 %a, i32 %b, i32 %c, i32 1, i32 2) #3
+ ret [2 x i64] %call
+}
+
+declare [2 x i64] @bar(i32, i32, i32, i32, i32) #1
diff --git a/llvm/test/CodeGen/BPF/arr_ret2.ll
b/llvm/test/CodeGen/BPF/arr_ret2.ll
new file mode 100644
index 0000000000000..f0c0b56f872ce
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/arr_ret2.ll
@@ -0,0 +1,12 @@
+; RUN: not llc -mtriple=bpf < %s 2> %t1
+; RUN: FileCheck %s < %t1
+; CHECK: only small returns
+
+; Function Attrs: nounwind uwtable
+define [3 x i32] @foo(i32 %a, i32 %b, i32 %c) #0 {
+entry:
+ %call = tail call [3 x i32] @bar(i32 %a, i32 %b, i32 %c, i32 1, i32 2) #3
+ ret [3 x i32] %call
+}
+
+declare [3 x i32] @bar(i32, i32, i32, i32, i32) #1
diff --git a/llvm/test/CodeGen/BPF/atomic-oversize.ll
b/llvm/test/CodeGen/BPF/atomic-oversize.ll
index 187f0964d4fb8..1bd5bc0f52c6a 100644
--- a/llvm/test/CodeGen/BPF/atomic-oversize.ll
+++ b/llvm/test/CodeGen/BPF/atomic-oversize.ll
@@ -1,11 +1,15 @@
; 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:
-; CHECK: call __atomic_load_16
-; CHECK: call __atomic_store_16
+; CHECK: r6 = r1
+; CHECK-NEXT: w2 = 0
+; CHECK-NEXT: call __atomic_load_16
+; CHECK-NEXT: r3 = r1
+; CHECK-NEXT: r1 = r6
+; CHECK-NEXT: r2 = r0
+; CHECK-NEXT: w4 = 0
+; CHECK-NEXT: call __atomic_store_16
%1 = load atomic i128, ptr %a monotonic, align 16
store atomic i128 %1, ptr %a monotonic, align 16
ret void
diff --git a/llvm/test/CodeGen/BPF/i128-bpf64.ll
b/llvm/test/CodeGen/BPF/i128-bpf64.ll
new file mode 100644
index 0000000000000..663fbe95c9c17
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/i128-bpf64.ll
@@ -0,0 +1,16 @@
+; RUN: llc -mtriple=bpf -mcpu=generic < %s | FileCheck %s
+
+define void @test(ptr %a) nounwind {
+; CHECK-LABEL: test:
+; CHECK: r6 = r1
+; CHECK-NEXT: r2 = 0
+; CHECK-NEXT: call __atomic_load_16
+; CHECK-NEXT: r3 = r1
+; CHECK-NEXT: r1 = r6
+; CHECK-NEXT: r2 = r0
+; CHECK-NEXT: r4 = 0
+; CHECK-NEXT: call __atomic_store_16
+ %1 = load atomic i128, ptr %a monotonic, align 16
+ store atomic i128 %1, ptr %a monotonic, align 16
+ ret void
+}
diff --git a/llvm/test/CodeGen/BPF/struct_ret1.ll
b/llvm/test/CodeGen/BPF/struct_ret1.ll
index 40d17ec514c48..fb3179c081c77 100644
--- a/llvm/test/CodeGen/BPF/struct_ret1.ll
+++ b/llvm/test/CodeGen/BPF/struct_ret1.ll
@@ -1,6 +1,5 @@
; RUN: not llc -mtriple=bpf < %s 2> %t1
; RUN: FileCheck %s < %t1
-; CHECK: error: <unknown>:0:0: in function bar { i64, i32 } (i32, i32, i32,
i32, i32): aggregate returns are not supported
%struct.S = type { i32, i32, i32 }
diff --git a/llvm/test/CodeGen/BPF/struct_ret2.ll
b/llvm/test/CodeGen/BPF/struct_ret2.ll
index 170d55cc29df0..1fac52d24abba 100644
--- a/llvm/test/CodeGen/BPF/struct_ret2.ll
+++ b/llvm/test/CodeGen/BPF/struct_ret2.ll
@@ -1,9 +1,10 @@
-; RUN: not llc -mtriple=bpf < %s 2> %t1
-; RUN: FileCheck %s < %t1
-; CHECK: only small returns
+; RUN: llc -mtriple=bpf < %s | FileCheck %s
; Function Attrs: nounwind uwtable
define { i64, i32 } @foo(i32 %a, i32 %b, i32 %c) #0 {
+; CHECK-LABEL: foo:
+; CHECK: w4 = 1
+; CHECK-NEXT: w5 = 2
entry:
%call = tail call { i64, i32 } @bar(i32 %a, i32 %b, i32 %c, i32 1, i32 2) #3
ret { i64, i32 } %call
diff --git a/llvm/test/CodeGen/BPF/struct_ret3.ll
b/llvm/test/CodeGen/BPF/struct_ret3.ll
new file mode 100644
index 0000000000000..8e649cc20055f
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/struct_ret3.ll
@@ -0,0 +1,12 @@
+; RUN: not llc -mtriple=bpf < %s 2> %t1
+; RUN: FileCheck %s < %t1
+; CHECK: only small returns
+
+; Function Attrs: nounwind uwtable
+define { i64, i32, i32 } @foo(i32 %a, i32 %b, i32 %c) #0 {
+entry:
+ %call = tail call { i64, i32, i32 } @bar(i32 %a, i32 %b, i32 %c, i32 1, i32
2) #3
+ ret { i64, i32, i32 } %call
+}
+
+declare { i64, i32, i32 } @bar(i32, i32, i32, i32, i32) #1
diff --git a/llvm/test/CodeGen/BPF/struct_ret4.ll
b/llvm/test/CodeGen/BPF/struct_ret4.ll
new file mode 100644
index 0000000000000..4c73f8754fbb8
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/struct_ret4.ll
@@ -0,0 +1,12 @@
+; RUN: not llc -mtriple=bpf < %s 2> %t1
+; RUN: FileCheck %s < %t1
+; CHECK: only small returns
+
+; Function Attrs: nounwind uwtable
+define { i32, i32, i32 } @foo(i32 %a, i32 %b, i32 %c) #0 {
+entry:
+ %call = tail call { i32, i32, i32 } @bar(i32 %a, i32 %b, i32 %c, i32 1, i32
2) #3
+ ret { i32, i32, i32 } %call
+}
+
+declare { i32, i32, i32 } @bar(i32, i32, i32, i32, i32) #1
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits