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

Reply via email to