[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-05-09 Thread via cfe-commits

https://github.com/yonghong-song closed 
https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-16 Thread via cfe-commits

https://github.com/yonghong-song edited 
https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-16 Thread via cfe-commits

https://github.com/yonghong-song updated 
https://github.com/llvm/llvm-project/pull/189060

>From d67d496fe0eba29b77eb5930c9dddc99fd56d8ba Mon Sep 17 00:00:00 2001
From: Yonghong Song 
Date: Wed, 18 Mar 2026 13:29:09 -0700
Subject: [PATCH 1/4] [BPF] Support Stack Arguments

Currently, bpf program and kfunc only support 5 register parameters.
As bpf community and use cases keep expanding, there are some need
to extend 5 register parameters by allocating additional parameters
on stack. There are two main use cases here:
  1. Currently kfunc is limited to 5 register parameters. In some
 special situation, people may want to have more than 5
 parameters. One of example is for sched_ext.
  2. Allowing more stack parameters can make bpf prog writer easier
 since they do not need to carefully limit the number of
 parameters for their programs.

The following is the high-level design:
  - Use bpf register R11 as the frame pointer to stack parameters.
This is to avoid mixing stacks due to R10.
  - Stack parameters must be after 5 register parameters.
  - All parameters should be at most 16 bytes as ByVal parameters
are not supported.
  - Support for cpu v1 to v4 so all cpu versions can use this.
A feature macro __BPF_FEATURE_STACK_ARGUMENT is defined
and users can check whether stack argument is supported or not.

The below is a simple asm code example about stack parameters:

  bar:
/* Retrieve two parameters from the caller of bar(). */
rX = *(u64 *)(r11 + 8)  // 1st arg
rY = *(u64 *)(r11 + 16) // 2nd arg
...
/* Prepare the single stack parameters for foo1 */
*(u64 *)(r11 - 8) = rZ  // 1st arg
call foo1
...
/* Prepare the single stack parameters for foo2 */
*(u64 *)(r11 - 16) = rX  // 1st arg
*(u64 *)(r11 - 8) = rY // 2nd arg
call foo2
...
  foo1:
/* Retrieve parameter '*(u64 *)(r11 - 8) = rZ' from bar(),
 * and assign the value rZ to rX.
 */
rX = *(u64 *)(r11 + 8)  // 1st arg
...
  foo2:
/* Retrieve parameters '*(u64 *)(r11 - 8/16) = rZ' from bar(),
 * and assign values rX/rY to rU/rV.
 */
rU = *(u64 *)(r11 + 8)  // 1st arg
rV = *(u64 *)(r11 + 16) // 2nd arg
...

The code patterns in the above try to follow x86_64/arm64 calling
conventions. That is, the first argument is in lower location than
the second argument, etc. The r11 based load should retrieve the value
directly from the caller stack. The r11 based store should push
the value directly on the specificed stack location.

Internally in bpf backend, pseudo insns are generated for
load_stack_arg and store_stack_arg. The BPFMIPeephole pass
changes pseudo insns into proper real bpf insns like the above.
---
 clang/lib/Basic/Targets/BPF.cpp   |   1 +
 .../test/Preprocessor/bpf-predefined-macros.c |   8 +
 llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp   |  32 +++
 llvm/lib/Target/BPF/BPFISelLowering.cpp   | 125 ---
 llvm/lib/Target/BPF/BPFISelLowering.h |   4 +-
 llvm/lib/Target/BPF/BPFInstrInfo.td   |  32 +++
 llvm/lib/Target/BPF/BPFMIPeephole.cpp |  60 ++
 llvm/lib/Target/BPF/BPFRegisterInfo.cpp   |   1 +
 llvm/lib/Target/BPF/BPFRegisterInfo.td|   4 +-
 .../BPF/Disassembler/BPFDisassembler.cpp  |  14 +-
 llvm/test/CodeGen/BPF/many_args1.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args2.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args3.ll   | 199 ++
 llvm/test/CodeGen/BPF/many_args4.ll   |  65 ++
 llvm/test/CodeGen/BPF/many_args5.ll   |  27 +++
 llvm/test/CodeGen/BPF/many_args6.ll   |  22 ++
 llvm/test/CodeGen/BPF/many_args7.ll   |  23 ++
 llvm/test/CodeGen/BPF/many_args8.ll   |  36 
 18 files changed, 617 insertions(+), 48 deletions(-)
 create mode 100644 llvm/test/CodeGen/BPF/many_args3.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args4.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args5.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args6.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args7.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args8.ll

diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp
index 8de1083d758c7..100769ea4cdb1 100644
--- a/clang/lib/Basic/Targets/BPF.cpp
+++ b/clang/lib/Basic/Targets/BPF.cpp
@@ -46,6 +46,7 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
   Builder.defineMacro("__BPF_FEATURE_ADDR_SPACE_CAST");
   Builder.defineMacro("__BPF_FEATURE_MAY_GOTO");
   Builder.defineMacro("__BPF_FEATURE_ATOMIC_MEM_ORDERING");
+  Builder.defineMacro("__BPF_FEATURE_STACK_ARGUMENT");
 
   if (CPU.empty())
 CPU = "v3";
diff --git a/clang/test/Preprocessor/bpf-predefined-macros.c 
b/clang/test/Preprocessor/bpf-predefined-macros.c
index b4e37fdd7de37..90287b7b24e95 100644
--- a/clang/test/Preprocessor/bpf-predefined-macros.c
+++ b/clang/test/Preprocessor/bpf-predefined-macros.c
@@ -76,6 +76,9 @@ int w;
 #ifdef 

[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-14 Thread via cfe-commits


@@ -0,0 +1,36 @@
+; RUN: not llc -mtriple=bpf -mcpu=v3 < %s 2> %t1

yonghong-song wrote:

Sure. Will update. all cpu versions should work.
BTW, Puranjay mentioned some issues with JIT. I summarized a comment in my v4 
patch. Please take a look. It will require llvm change.

https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-14 Thread via cfe-commits


@@ -0,0 +1,36 @@
+; RUN: not llc -mtriple=bpf -mcpu=v3 < %s 2> %t1

4ast wrote:

why tests with structs are v3 only? all mcpu-s should work the same, no?

https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-14 Thread via cfe-commits


@@ -504,8 +539,9 @@ SDValue 
BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
 
   unsigned NumBytes = CCInfo.getStackSize();
 
-  if (Outs.size() > MaxArgs)
-fail(CLI.DL, DAG, "too many arguments", Callee);
+  if (hasSplitArg(ArgLocs, [&](size_t I) { return Outs[I].OrigArgIndex; }))

4ast wrote:

> I guess we can support this feature (16-byte cross register and stack) in the 
> compiler. Currently verifier does not support 16-byte arguments and we can 
> figure out how to do it in verifier and jit.

Yes. Let's do full support in LLVM though verifier won't understand it yet. As 
long as it matches x86/arm64 we're fine picking the same for bpf psABI.

https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-14 Thread via cfe-commits


@@ -504,8 +539,9 @@ SDValue 
BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
 
   unsigned NumBytes = CCInfo.getStackSize();
 
-  if (Outs.size() > MaxArgs)
-fail(CLI.DL, DAG, "too many arguments", Callee);
+  if (hasSplitArg(ArgLocs, [&](size_t I) { return Outs[I].OrigArgIndex; }))

4ast wrote:

> I did this due to X86_64 calling convention. For example, for x86, we have
> 
> ```
> struct t {long a; long b;};
> int foo(int a, int b, int c, int d, int e, struct t f, int g) { ... }
> ```
> 
> What it actually is "a: RDI, b: RSI, c: RDX, d: RCX, e: R8, g: R9, f: on the 
> stack". Do we want to follow X86 calling convention like the above?

yes. we should do the same

https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-14 Thread via cfe-commits

https://github.com/yonghong-song updated 
https://github.com/llvm/llvm-project/pull/189060

>From d67d496fe0eba29b77eb5930c9dddc99fd56d8ba Mon Sep 17 00:00:00 2001
From: Yonghong Song 
Date: Wed, 18 Mar 2026 13:29:09 -0700
Subject: [PATCH 1/3] [BPF] Support Stack Arguments

Currently, bpf program and kfunc only support 5 register parameters.
As bpf community and use cases keep expanding, there are some need
to extend 5 register parameters by allocating additional parameters
on stack. There are two main use cases here:
  1. Currently kfunc is limited to 5 register parameters. In some
 special situation, people may want to have more than 5
 parameters. One of example is for sched_ext.
  2. Allowing more stack parameters can make bpf prog writer easier
 since they do not need to carefully limit the number of
 parameters for their programs.

The following is the high-level design:
  - Use bpf register R11 as the frame pointer to stack parameters.
This is to avoid mixing stacks due to R10.
  - Stack parameters must be after 5 register parameters.
  - All parameters should be at most 16 bytes as ByVal parameters
are not supported.
  - Support for cpu v1 to v4 so all cpu versions can use this.
A feature macro __BPF_FEATURE_STACK_ARGUMENT is defined
and users can check whether stack argument is supported or not.

The below is a simple asm code example about stack parameters:

  bar:
/* Retrieve two parameters from the caller of bar(). */
rX = *(u64 *)(r11 + 8)  // 1st arg
rY = *(u64 *)(r11 + 16) // 2nd arg
...
/* Prepare the single stack parameters for foo1 */
*(u64 *)(r11 - 8) = rZ  // 1st arg
call foo1
...
/* Prepare the single stack parameters for foo2 */
*(u64 *)(r11 - 16) = rX  // 1st arg
*(u64 *)(r11 - 8) = rY // 2nd arg
call foo2
...
  foo1:
/* Retrieve parameter '*(u64 *)(r11 - 8) = rZ' from bar(),
 * and assign the value rZ to rX.
 */
rX = *(u64 *)(r11 + 8)  // 1st arg
...
  foo2:
/* Retrieve parameters '*(u64 *)(r11 - 8/16) = rZ' from bar(),
 * and assign values rX/rY to rU/rV.
 */
rU = *(u64 *)(r11 + 8)  // 1st arg
rV = *(u64 *)(r11 + 16) // 2nd arg
...

The code patterns in the above try to follow x86_64/arm64 calling
conventions. That is, the first argument is in lower location than
the second argument, etc. The r11 based load should retrieve the value
directly from the caller stack. The r11 based store should push
the value directly on the specificed stack location.

Internally in bpf backend, pseudo insns are generated for
load_stack_arg and store_stack_arg. The BPFMIPeephole pass
changes pseudo insns into proper real bpf insns like the above.
---
 clang/lib/Basic/Targets/BPF.cpp   |   1 +
 .../test/Preprocessor/bpf-predefined-macros.c |   8 +
 llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp   |  32 +++
 llvm/lib/Target/BPF/BPFISelLowering.cpp   | 125 ---
 llvm/lib/Target/BPF/BPFISelLowering.h |   4 +-
 llvm/lib/Target/BPF/BPFInstrInfo.td   |  32 +++
 llvm/lib/Target/BPF/BPFMIPeephole.cpp |  60 ++
 llvm/lib/Target/BPF/BPFRegisterInfo.cpp   |   1 +
 llvm/lib/Target/BPF/BPFRegisterInfo.td|   4 +-
 .../BPF/Disassembler/BPFDisassembler.cpp  |  14 +-
 llvm/test/CodeGen/BPF/many_args1.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args2.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args3.ll   | 199 ++
 llvm/test/CodeGen/BPF/many_args4.ll   |  65 ++
 llvm/test/CodeGen/BPF/many_args5.ll   |  27 +++
 llvm/test/CodeGen/BPF/many_args6.ll   |  22 ++
 llvm/test/CodeGen/BPF/many_args7.ll   |  23 ++
 llvm/test/CodeGen/BPF/many_args8.ll   |  36 
 18 files changed, 617 insertions(+), 48 deletions(-)
 create mode 100644 llvm/test/CodeGen/BPF/many_args3.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args4.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args5.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args6.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args7.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args8.ll

diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp
index 8de1083d758c7..100769ea4cdb1 100644
--- a/clang/lib/Basic/Targets/BPF.cpp
+++ b/clang/lib/Basic/Targets/BPF.cpp
@@ -46,6 +46,7 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
   Builder.defineMacro("__BPF_FEATURE_ADDR_SPACE_CAST");
   Builder.defineMacro("__BPF_FEATURE_MAY_GOTO");
   Builder.defineMacro("__BPF_FEATURE_ATOMIC_MEM_ORDERING");
+  Builder.defineMacro("__BPF_FEATURE_STACK_ARGUMENT");
 
   if (CPU.empty())
 CPU = "v3";
diff --git a/clang/test/Preprocessor/bpf-predefined-macros.c 
b/clang/test/Preprocessor/bpf-predefined-macros.c
index b4e37fdd7de37..90287b7b24e95 100644
--- a/clang/test/Preprocessor/bpf-predefined-macros.c
+++ b/clang/test/Preprocessor/bpf-predefined-macros.c
@@ -76,6 +76,9 @@ int w;
 #ifdef 

[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-14 Thread via cfe-commits

https://github.com/yonghong-song updated 
https://github.com/llvm/llvm-project/pull/189060

>From d67d496fe0eba29b77eb5930c9dddc99fd56d8ba Mon Sep 17 00:00:00 2001
From: Yonghong Song 
Date: Wed, 18 Mar 2026 13:29:09 -0700
Subject: [PATCH 1/3] [BPF] Support Stack Arguments

Currently, bpf program and kfunc only support 5 register parameters.
As bpf community and use cases keep expanding, there are some need
to extend 5 register parameters by allocating additional parameters
on stack. There are two main use cases here:
  1. Currently kfunc is limited to 5 register parameters. In some
 special situation, people may want to have more than 5
 parameters. One of example is for sched_ext.
  2. Allowing more stack parameters can make bpf prog writer easier
 since they do not need to carefully limit the number of
 parameters for their programs.

The following is the high-level design:
  - Use bpf register R11 as the frame pointer to stack parameters.
This is to avoid mixing stacks due to R10.
  - Stack parameters must be after 5 register parameters.
  - All parameters should be at most 16 bytes as ByVal parameters
are not supported.
  - Support for cpu v1 to v4 so all cpu versions can use this.
A feature macro __BPF_FEATURE_STACK_ARGUMENT is defined
and users can check whether stack argument is supported or not.

The below is a simple asm code example about stack parameters:

  bar:
/* Retrieve two parameters from the caller of bar(). */
rX = *(u64 *)(r11 + 8)  // 1st arg
rY = *(u64 *)(r11 + 16) // 2nd arg
...
/* Prepare the single stack parameters for foo1 */
*(u64 *)(r11 - 8) = rZ  // 1st arg
call foo1
...
/* Prepare the single stack parameters for foo2 */
*(u64 *)(r11 - 16) = rX  // 1st arg
*(u64 *)(r11 - 8) = rY // 2nd arg
call foo2
...
  foo1:
/* Retrieve parameter '*(u64 *)(r11 - 8) = rZ' from bar(),
 * and assign the value rZ to rX.
 */
rX = *(u64 *)(r11 + 8)  // 1st arg
...
  foo2:
/* Retrieve parameters '*(u64 *)(r11 - 8/16) = rZ' from bar(),
 * and assign values rX/rY to rU/rV.
 */
rU = *(u64 *)(r11 + 8)  // 1st arg
rV = *(u64 *)(r11 + 16) // 2nd arg
...

The code patterns in the above try to follow x86_64/arm64 calling
conventions. That is, the first argument is in lower location than
the second argument, etc. The r11 based load should retrieve the value
directly from the caller stack. The r11 based store should push
the value directly on the specificed stack location.

Internally in bpf backend, pseudo insns are generated for
load_stack_arg and store_stack_arg. The BPFMIPeephole pass
changes pseudo insns into proper real bpf insns like the above.
---
 clang/lib/Basic/Targets/BPF.cpp   |   1 +
 .../test/Preprocessor/bpf-predefined-macros.c |   8 +
 llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp   |  32 +++
 llvm/lib/Target/BPF/BPFISelLowering.cpp   | 125 ---
 llvm/lib/Target/BPF/BPFISelLowering.h |   4 +-
 llvm/lib/Target/BPF/BPFInstrInfo.td   |  32 +++
 llvm/lib/Target/BPF/BPFMIPeephole.cpp |  60 ++
 llvm/lib/Target/BPF/BPFRegisterInfo.cpp   |   1 +
 llvm/lib/Target/BPF/BPFRegisterInfo.td|   4 +-
 .../BPF/Disassembler/BPFDisassembler.cpp  |  14 +-
 llvm/test/CodeGen/BPF/many_args1.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args2.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args3.ll   | 199 ++
 llvm/test/CodeGen/BPF/many_args4.ll   |  65 ++
 llvm/test/CodeGen/BPF/many_args5.ll   |  27 +++
 llvm/test/CodeGen/BPF/many_args6.ll   |  22 ++
 llvm/test/CodeGen/BPF/many_args7.ll   |  23 ++
 llvm/test/CodeGen/BPF/many_args8.ll   |  36 
 18 files changed, 617 insertions(+), 48 deletions(-)
 create mode 100644 llvm/test/CodeGen/BPF/many_args3.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args4.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args5.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args6.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args7.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args8.ll

diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp
index 8de1083d758c7..100769ea4cdb1 100644
--- a/clang/lib/Basic/Targets/BPF.cpp
+++ b/clang/lib/Basic/Targets/BPF.cpp
@@ -46,6 +46,7 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
   Builder.defineMacro("__BPF_FEATURE_ADDR_SPACE_CAST");
   Builder.defineMacro("__BPF_FEATURE_MAY_GOTO");
   Builder.defineMacro("__BPF_FEATURE_ATOMIC_MEM_ORDERING");
+  Builder.defineMacro("__BPF_FEATURE_STACK_ARGUMENT");
 
   if (CPU.empty())
 CPU = "v3";
diff --git a/clang/test/Preprocessor/bpf-predefined-macros.c 
b/clang/test/Preprocessor/bpf-predefined-macros.c
index b4e37fdd7de37..90287b7b24e95 100644
--- a/clang/test/Preprocessor/bpf-predefined-macros.c
+++ b/clang/test/Preprocessor/bpf-predefined-macros.c
@@ -76,6 +76,9 @@ int w;
 #ifdef 

[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-13 Thread via cfe-commits

https://github.com/yonghong-song updated 
https://github.com/llvm/llvm-project/pull/189060

>From 504cc29ffc0d85339120635a65ab9ff5ddf14498 Mon Sep 17 00:00:00 2001
From: Yonghong Song 
Date: Wed, 18 Mar 2026 13:29:09 -0700
Subject: [PATCH 1/2] [BPF] Support Stack Arguments

Currently, bpf program and kfunc only support 5 register parameters.
As bpf community and use cases keep expanding, there are some need
to extend 5 register parameters by allocating additional parameters
on stack. There are two main use cases here:
  1. Currently kfunc is limited to 5 register parameters. In some
 special situation, people may want to have more than 5
 parameters. One of example is for sched_ext.
  2. Allowing more stack parameters can make bpf prog writer easier
 since they do not need to carefully limit the number of
 parameters for their programs.

The following is the high-level design:
  - Use bpf register R11 as the frame pointer to stack parameters.
This is to avoid mixing stacks due to R10.
  - Stack parameters must be after 5 register parameters.
  - All parameters should be at most 16 bytes as ByVal parameters
are not supported.
  - Support for cpu v1 to v4 so all cpu versions can use this.
A feature macro __BPF_FEATURE_STACK_ARGUMENT is defined
and users can check whether stack argument is supported or not.

The below is a simple asm code example about stack parameters:

  bar:
/* Retrieve two parameters from the caller of bar(). */
rX = *(u64 *)(r11 + 8)  // 1st arg
rY = *(u64 *)(r11 + 16) // 2nd arg
...
/* Prepare the single stack parameters for foo1 */
*(u64 *)(r11 - 8) = rZ  // 1st arg
call foo1
...
/* Prepare the single stack parameters for foo2 */
*(u64 *)(r11 - 16) = rX  // 1st arg
*(u64 *)(r11 - 8) = rY // 2nd arg
call foo2
...
  foo1:
/* Retrieve parameter '*(u64 *)(r11 - 8) = rZ' from bar(),
 * and assign the value rZ to rX.
 */
rX = *(u64 *)(r11 + 8)  // 1st arg
...
  foo2:
/* Retrieve parameters '*(u64 *)(r11 - 8/16) = rZ' from bar(),
 * and assign values rX/rY to rU/rV.
 */
rU = *(u64 *)(r11 + 8)  // 1st arg
rV = *(u64 *)(r11 + 16) // 2nd arg
...

The code patterns in the above try to follow x86_64/arm64 calling
conventions. That is, the first argument is in lower location than
the second argument, etc. The r11 based load should retrieve the value
directly from the caller stack. The r11 based store should push
the value directly on the specificed stack location.

Internally in bpf backend, pseudo insns are generated for
load_stack_arg and store_stack_arg. The BPFMIPeephole pass
changes pseudo insns into proper real bpf insns like the above.
---
 clang/lib/Basic/Targets/BPF.cpp   |   1 +
 .../test/Preprocessor/bpf-predefined-macros.c |   8 +
 llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp   |  32 +++
 llvm/lib/Target/BPF/BPFISelLowering.cpp   | 125 ---
 llvm/lib/Target/BPF/BPFISelLowering.h |   4 +-
 llvm/lib/Target/BPF/BPFInstrInfo.td   |  32 +++
 llvm/lib/Target/BPF/BPFMIPeephole.cpp |  60 ++
 llvm/lib/Target/BPF/BPFRegisterInfo.cpp   |   1 +
 llvm/lib/Target/BPF/BPFRegisterInfo.td|   4 +-
 .../BPF/Disassembler/BPFDisassembler.cpp  |  14 +-
 llvm/test/CodeGen/BPF/many_args1.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args2.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args3.ll   | 199 ++
 llvm/test/CodeGen/BPF/many_args4.ll   |  65 ++
 llvm/test/CodeGen/BPF/many_args5.ll   |  27 +++
 llvm/test/CodeGen/BPF/many_args6.ll   |  22 ++
 llvm/test/CodeGen/BPF/many_args7.ll   |  23 ++
 llvm/test/CodeGen/BPF/many_args8.ll   |  36 
 18 files changed, 617 insertions(+), 48 deletions(-)
 create mode 100644 llvm/test/CodeGen/BPF/many_args3.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args4.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args5.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args6.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args7.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args8.ll

diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp
index 8de1083d758c7..100769ea4cdb1 100644
--- a/clang/lib/Basic/Targets/BPF.cpp
+++ b/clang/lib/Basic/Targets/BPF.cpp
@@ -46,6 +46,7 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
   Builder.defineMacro("__BPF_FEATURE_ADDR_SPACE_CAST");
   Builder.defineMacro("__BPF_FEATURE_MAY_GOTO");
   Builder.defineMacro("__BPF_FEATURE_ATOMIC_MEM_ORDERING");
+  Builder.defineMacro("__BPF_FEATURE_STACK_ARGUMENT");
 
   if (CPU.empty())
 CPU = "v3";
diff --git a/clang/test/Preprocessor/bpf-predefined-macros.c 
b/clang/test/Preprocessor/bpf-predefined-macros.c
index b4e37fdd7de37..90287b7b24e95 100644
--- a/clang/test/Preprocessor/bpf-predefined-macros.c
+++ b/clang/test/Preprocessor/bpf-predefined-macros.c
@@ -76,6 +76,9 @@ int w;
 #ifdef 

[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-10 Thread via cfe-commits

yonghong-song wrote:

> > we can enforce r12 based stores like below:
> > 
> > * r12 based stores must be before a call in the same basic block
> > * there should not be any r12 based loads between the first stores and the 
> > call.
> >   The above is exactly what the llvm generates.
> 
> we cannot do it. There are too many restrictions already. All current 
> restrictions need to be removed. I guess it's fine just doing the max across 
> all and reserver in the prologue for now.

Okay, I will keep the current JIT implementation for now.


https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-10 Thread via cfe-commits

4ast wrote:

> we can enforce r12 based stores like below:
> 
> * r12 based stores must be before a call in the same basic block
> * there should not be any r12 based loads between the first stores and the 
> call.
>   The above is exactly what the llvm generates.

we cannot do it. There are too many restrictions already. All current 
restrictions need to be removed.
I guess it's fine just doing the max across all and reserver in the prologue 
for now.

https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-10 Thread via cfe-commits

yonghong-song wrote:

I struggled with claude and didn't get a good solution for random placement of 
r12 related instructions. I think we can enforce more restrictions in verifier 
in order to minimize the stack usage.

The following is an example:
```
$ cat t.c
__attribute__((noinline)) static int foo1(int a1, int a2, int a3, int a4, int 
a5, int a6, int a7) {
  return a1 + a2 + a3 + a4 + a5 + a6 + a7;
}
__attribute__((noinline)) static int foo2(int a1, int a2, int a3, int a4, int 
a5, int a6, int a7, int a8) {
  return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8;
}

int bar(int a1, int a2, int a3, int a4, int a5, int a6, int a7) {
  int ret;

  if (a1 + a2)
ret = foo1(a1, a2, a3, a4, a5, a6, a7);
  else
ret = foo2(a1, a2, a3, a4, a5, a6, a7, a6 + a7);
  return ret + a3 + a4;
}
```
Compiled with 'clang --target=bpf -O2 -S t.c', I got the following:
```
.file   "t.c"   
  
.text   
  
.globl  bar # -- Begin function bar 
  
.p2align3   
  
.type   bar,@function   
  
bar:# @bar  
  
# %bb.0:
  
w6 = w4 
  
w7 = w3 
  
r4 = *(u64 *)(r12 + 8)  
  
r3 = *(u64 *)(r12 + 16) 
  
w0 = w2 
  
w0 = -w0
  
if w1 == w0 goto .LBB0_2
  
# %bb.1:
  
*(u64 *)(r12 - 16) = r4 
  
*(u64 *)(r12 - 8) = r3  
  
w3 = w7 
  
w4 = w6 
  
call foo1   
  
goto .LBB0_3
  
.LBB0_2:
  
*(u64 *)(r12 - 24) = r4
*(u64 *)(r12 - 16) = r3
w3 += w4
*(u64 *)(r12 - 8) = r3
w3 = w7
w4 = w6
call foo2
.LBB0_3:
w6 += w7
w6 += w0
w0 = w6
exit
.Lfunc_end0:
.size   bar, .Lfunc_end0-bar
# -- End function
.p2align3   # -- Begin function foo1
.type   foo1,@function
foo1:   # @foo1
# %bb.0:
w0 = w2
w0 += w1
w0 += w3
w0 += w4
w0 += w5
r1 = *(u64 *)(r12 + 8)
w0 += w1
r1 = *(u64 *)(r12 + 16)
w0 += w1
exit
.Lfunc_end1:
.size   foo1, .Lfunc_end1-foo1
# -- End function
.p2align3   # 

[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-09 Thread via cfe-commits

yonghong-song wrote:

> > For store, we could do hit the first store, do adjustment 'r12 += ' then 
> > for the rest stores, there is no need for adjustment hit a call. In this 
> > case, do 'r12 -= '.
> 
> to know 'first store' JIT would need to do data flow analysis, which is not 
> feasible.
> 
> > My current thinking is there is no need to do explicit 12 adjustments, 
> > e.g., to accommodate with code sequences like the above. Second, for each 
> > store for x86, the offset adjustment is done in jit time. So at runtime, we 
> > have no overhead at all.
> 
> right, no extra overhead is mandatory, but I'm still missing how you think 
> JIT will do the adjustment. Like compute the maximum of all *(r12 - N) = .. 
> insn and use that in the prologue ? 

yes. This is what I did in the patch. Compute the number of stack augument 
consumption for each callee and get the maximum one. And this maximum one is 
used in jit for stack allocation before the main loop.

> I guess it works, but then this function will reserve more stack then it 
> needs. like foo() { bar(); // with deep callchain

Sadly yes, esp. for deep callchain.

I previously thought about this whether we could allocate stacks based on each 
callee. And discussed with claude and claude suggests to use the current 
approach as alternative one (with minimum stack usage) is very complex to 
implement. Since you are mentioning this again, let me think whether we can 
find a way with reasonable complexity to implement this.

> 
> meh(lots of args); } the space needed to call meh() will be reserved upfront, 
> so unnecessary stack waste while calling bar() ? For JIT to reserve it right 
> before meh() it would need to know 'first store' and then consider all 
> possible combinations of calling meh(). gets tricky.



https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-09 Thread via cfe-commits

4ast wrote:


> For store, we could do hit the first store, do adjustment 'r12 += ' then for 
> the rest stores, there is no need for adjustment hit a call. In this case, do 
> 'r12 -= '.

to know 'first store' JIT would need to do data flow analysis, which is not 
feasible.
 
> My current thinking is there is no need to do explicit 12 adjustments, e.g., 
> to accommodate with code sequences like the above. Second, for each store for 
> x86, the offset adjustment is done in jit time. So at runtime, we have no 
> overhead at all.

right, no extra overhead is mandatory, but I'm still missing how you think JIT 
will do the adjustment.
Like compute the maximum of all *(r12 - N) = .. insn and use that in the 
prologue ?
I guess it works, but then this function will reserve more stack then it needs.
like
foo()
{ 
   bar(); // with deep callchain
   
   meh(lots of args);
}
the space needed to call meh() will be reserved upfront, so unnecessary stack 
waste while calling bar() ?
For JIT to reserve it right before meh() it would need to know 'first store' 
and then consider all possible combinations of calling meh(). gets tricky.

https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-08 Thread via cfe-commits

4ast wrote:

> > if JIT did 'sp -=' just before the call then it's broken. The code cannot 
> > store into sp - X before sp -=, since IRQ will corrupt it. Hence my earlier 
> > point that JIT has to insert 'sp -=' before the actual stores.
> 
> Ya. I should clarify. 'before the call' is not precise. The extra stack is 
> allocated before the main loop (going through all insns). So we should be 
> okay.

so what are you saying? yes or no to explicit r12 adjustment?

https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-08 Thread via cfe-commits

yonghong-song wrote:

> > > if JIT did 'sp -=' just before the call then it's broken. The code cannot 
> > > store into sp - X before sp -=, since IRQ will corrupt it. Hence my 
> > > earlier point that JIT has to insert 'sp -=' before the actual stores.
> > 
> > 
> > Ya. I should clarify. 'before the call' is not precise. The extra stack is 
> > allocated before the main loop (going through all insns). So we should be 
> > okay.
> 
> so what are you saying? yes or no to explicit r12 adjustment?

Probably not. As you mentioned earlier with case
  r1 = *(u64 *)(r12 + 16)
  *(u64 *)(r12 - 8) = r1
  r1 = *(u64 *)(r12 + 8)
  *(u64 *)(r12 - 16) = r1
In such cases, if we want to adjust, we will have to adjust per insn base and 
it is not efficient.

But if all loads are before stores, we could do some adjustment. Currently for 
load, there is no need to do adjustment as the arch offset already matches r12 
offset. For store, we could do
  hit the first store, do adjustment 'r12 += '
  then for the rest stores, there is no need for adjustment
  hit a call. In this case, do 'r12 -= '.

My current thinking is there is no need to do explicit 12 adjustments, e.g., to 
accommodate with code sequences like the above. Second, for each store for x86, 
the offset adjustment is done in jit time. So at runtime, we have no overhead 
at all.

https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-07 Thread via cfe-commits

yonghong-song wrote:


> if JIT did 'sp -=' just before the call then it's broken. The code cannot 
> store into sp - X before sp -=, since IRQ will corrupt it. Hence my earlier 
> point that JIT has to insert 'sp -=' before the actual stores.

Ya. I should clarify. 'before the call' is not precise. The extra stack is 
allocated before the main loop (going through all insns). So we should be okay.



https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-07 Thread via cfe-commits

4ast wrote:

> 
> For x86, we also did 'sp -= ' before the call. With this, for '*(u64 *)(r12 - 
> off) = ' can directly put the value in the expected stack location. After the 
> call, the jit will do 'sp += ' to go to the place where all "pushed" values 
> are gone.

if JIT did 'sp -=' just before the call then it's broken. The code cannot store 
into sp - X before sp -=, since IRQ will corrupt it.
Hence my earlier point that JIT has to insert 'sp -=' before the actual stores.


https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-07 Thread via cfe-commits

4ast wrote:

both archs have:
  callq   foo
  addq$32, %rsp
after the call,
and arm64 does 'sub  sp, sp, #48' before the call.
while x86 does implicit rsp adjustment via push before the call.
Should we do r12 -= const before the call and corresponding r12 += const after?
That will help JIT a bit.
Then both arg-in and arg-out will be accessed via [r12 + 0], [r12 + 8] which 
has its pros and cons.
Consider the case when 7th incoming arg needs to be passed as 7th outgoing.
With the current patch the compiler can emit it as:
r1 = *(u64 *)(r12 + 16)
*(u64 *)(r12 - 8) = r1

with explicit r12 adjustment:
r1 = *(u64 *)(r12 + 16)
r12 += 16
*(u64 *)(r12 +16) = r1

but without explicit r12 adjustment JIT would need to insert it somewhere, and 
if the sequence is:
r1 = *(u64 *)(r12 + 16)
*(u64 *)(r12 - 8) = r1
r1 = *(u64 *)(r12 + 8)
*(u64 *)(r12 - 16) = r1

there is no place for JIT to insert it unless it maps r12 with positive offset 
to, say, %rsp,
and r12 with negative offset as %rbp ?
the might be other gotchas with and without explicit r12. Something to think 
through.


https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-06 Thread via cfe-commits

yonghong-song wrote:

The following is an example:
```
extern long tar(void);
 __attribute__((noinline))
long foo(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int 
a9, int a10) {
  return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10;
}
long bar(void) { return foo(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + tar(); }
```
Compiled with 'clang -O2 -S t.c' on both x86_64 and arm64 machines.

For x86_64 asm:
```
...
foo:# @foo
.cfi_startproc
# %bb.0:
addl%esi, %edi
addl%ecx, %edx
addl%edi, %edx
addl%r9d, %r8d
addl%edx, %r8d
addl8(%rsp), %r8d
addl16(%rsp), %r8d
addl24(%rsp), %r8d
addl32(%rsp), %r8d
movslq  %r8d, %rax
retq
...
bar:# @bar
.cfi_startproc
# %bb.0:
pushq   %rbx
.cfi_def_cfa_offset 16
.cfi_offset %rbx, -16
movl$1, %edi
movl$2, %esi
movl$3, %edx
movl$4, %ecx
movl$5, %r8d
movl$6, %r9d
pushq   $10
.cfi_adjust_cfa_offset 8
pushq   $9
.cfi_adjust_cfa_offset 8
pushq   $8
.cfi_adjust_cfa_offset 8
pushq   $7
.cfi_adjust_cfa_offset 8
callq   foo
addq$32, %rsp
.cfi_adjust_cfa_offset -32
movq%rax, %rbx
callq   tar@PLT
addq%rbx, %rax
popq%rbx
.cfi_def_cfa_offset 8
retq
```
You can see that for bar(), argument 6 is moved to r9. Argument 7-10 is pushed 
in reverse order.
For foo(), the incoming stack arguments are retrieved by going to caller.

The following is a arm64 asm snippet:

```
...
foo:// @foo
.cfi_startproc
// %bb.0:
ldr w8, [sp]
add w9, w1, w0
add w10, w2, w3
add w11, w4, w5
add w9, w9, w10
add w10, w11, w6
ldr w11, [sp, #8]
add w8, w7, w8
add w9, w9, w10
add w8, w9, w8
add w8, w8, w11
sxtwx0, w8
ret
...
bar:// @bar
.cfi_startproc
// %bb.0:
sub sp, sp, #48
.cfi_def_cfa_offset 48
stp x29, x30, [sp, #16] // 16-byte Folded Spill
str x19, [sp, #32]  // 8-byte Spill
add x29, sp, #16
.cfi_def_cfa w29, 32
.cfi_offset w19, -16
.cfi_offset w30, -24
.cfi_offset w29, -32
mov w8, #10 // =0xa
mov w9, #9  // =0x9
mov w0, #1  // =0x1
mov w1, #2  // =0x2
mov w2, #3  // =0x3
mov w3, #4  // =0x4
mov w4, #5  // =0x5
mov w5, #6  // =0x6
mov w6, #7  // =0x7
mov w7, #8  // =0x8
str w8, [sp, #8]
str w9, [sp]
bl  foo
mov x19, x0
bl  tar
add x0, x0, x19
.cfi_def_cfa wsp, 48
ldp x29, x30, [sp, #16] // 16-byte Folded Reload
ldr x19, [sp, #32]  // 8-byte Reload
add sp, sp, #48
.cfi_def_cfa_offset 0
.cfi_restore w19
.cfi_restore w30
.cfi_restore w29
ret
...
```
For arm64, the first 8 parameters can be passed through registers. The number 9 
and 10 parameters are saved in stack. Look at the above code
```
mov w8, #10 // =0xa
mov w9, #9  // =0x9
...
str w8, [sp, #8]
str w9, [sp]
```
So w8 (the second stack argument) is in [sp + 8], and w9 (the first stack 
argument) is in [sp]. So stack layout will be
```
second stack argument (argument number 10)
first stack argument (argument number 9)
```
Similar to x86_64 calling convention.

https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-06 Thread via cfe-commits

https://github.com/yonghong-song updated 
https://github.com/llvm/llvm-project/pull/189060

>From b4d84408720cbdf5bf817044baa2bf952d1b4442 Mon Sep 17 00:00:00 2001
From: Yonghong Song 
Date: Wed, 18 Mar 2026 13:29:09 -0700
Subject: [PATCH] [BPF] Support Stack Arguments

Currently, bpf program and kfunc only support 5 register parameters.
As bpf community and use cases keep expanding, there are some need
to extend 5 register parameters by allocating additional parameters
on stack. There are two main use cases here:
  1. Currently kfunc is limited to 5 register parameters. In some
 special situation, people may want to have more than 5
 parameters. One of example is for sched_ext.
  2. Allowing more stack parameters can make bpf prog writer easier
 since they do not need to carefully limit the number of
 parameters for their programs.

The following is the high-level design:
  - Use bpf register R12 as the frame pointer to stack parameters.
This is to avoid mixing stacks due to R10.
  - Stack parameters must be after 5 register parameters.
  - All parameters should be at most 16 bytes as ByVal parameters
are not supported.
  - Support for cpu v1 to v4 so all cpu versions can use this.
A feature macro __BPF_FEATURE_STACK_ARGUMENT is defined
and users can check whether stack argument is supported or not.

The below is a simple asm code example about stack parameters:

  bar:
/* Retrieve two parameters from the caller of bar(). */
rX = *(u64 *)(r12 + 8)  // 1st arg
rY = *(u64 *)(r12 + 16) // 2nd arg
...
/* Prepare the single stack parameters for foo1 */
*(u64 *)(r12 - 8) = rZ  // 1st arg
call foo1
...
/* Prepare the single stack parameters for foo2 */
*(u64 *)(r12 - 16) = rX  // 1st arg
*(u64 *)(r12 - 8) = rY // 2nd arg
call foo2
...
  foo1:
/* Retrieve parameter '*(u64 *)(r12 - 8) = rZ' from bar(),
 * and assign the value rZ to rX.
 */
rX = *(u64 *)(r12 + 8)  // 1st arg
...
  foo2:
/* Retrieve parameters '*(u64 *)(r12 - 8/16) = rZ' from bar(),
 * and assign values rX/rY to rU/rV.
 */
rU = *(u64 *)(r12 + 8)  // 1st arg
rV = *(u64 *)(r12 + 16) // 2nd arg
...

The code patterns in the above try to follow x86_64/arm64 calling
conventions. That is, the first argument is in lower location than
the second argument, etc. The r12 based load should retrieve the value
directly from the caller stack. The r12 based store should push
the value directly on the specificed stack location.

Internally in bpf backend, pseudo insns are generated for
load_stack_arg and store_stack_arg. The BPFMIPeephole pass
changes pseudo insns into proper real bpf insns like the above.
---
 clang/lib/Basic/Targets/BPF.cpp   |   1 +
 .../test/Preprocessor/bpf-predefined-macros.c |   8 +
 llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp   |  32 +++
 llvm/lib/Target/BPF/BPFISelLowering.cpp   | 125 ---
 llvm/lib/Target/BPF/BPFISelLowering.h |   4 +-
 llvm/lib/Target/BPF/BPFInstrInfo.td   |  32 +++
 llvm/lib/Target/BPF/BPFMIPeephole.cpp |  60 ++
 llvm/lib/Target/BPF/BPFRegisterInfo.cpp   |   1 +
 llvm/lib/Target/BPF/BPFRegisterInfo.td|   4 +-
 .../BPF/Disassembler/BPFDisassembler.cpp  |  14 +-
 llvm/test/CodeGen/BPF/many_args1.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args2.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args3.ll   | 199 ++
 llvm/test/CodeGen/BPF/many_args4.ll   |  65 ++
 llvm/test/CodeGen/BPF/many_args5.ll   |  27 +++
 llvm/test/CodeGen/BPF/many_args6.ll   |  22 ++
 llvm/test/CodeGen/BPF/many_args7.ll   |  23 ++
 llvm/test/CodeGen/BPF/many_args8.ll   |  36 
 18 files changed, 617 insertions(+), 48 deletions(-)
 create mode 100644 llvm/test/CodeGen/BPF/many_args3.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args4.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args5.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args6.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args7.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args8.ll

diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp
index 8de1083d758c7..100769ea4cdb1 100644
--- a/clang/lib/Basic/Targets/BPF.cpp
+++ b/clang/lib/Basic/Targets/BPF.cpp
@@ -46,6 +46,7 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
   Builder.defineMacro("__BPF_FEATURE_ADDR_SPACE_CAST");
   Builder.defineMacro("__BPF_FEATURE_MAY_GOTO");
   Builder.defineMacro("__BPF_FEATURE_ATOMIC_MEM_ORDERING");
+  Builder.defineMacro("__BPF_FEATURE_STACK_ARGUMENT");
 
   if (CPU.empty())
 CPU = "v3";
diff --git a/clang/test/Preprocessor/bpf-predefined-macros.c 
b/clang/test/Preprocessor/bpf-predefined-macros.c
index b4e37fdd7de37..90287b7b24e95 100644
--- a/clang/test/Preprocessor/bpf-predefined-macros.c
+++ b/clang/test/Preprocessor/bpf-predefined-macros.c
@@ -76,6 +76,9 @@ int w;
 #ifdef 

[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-06 Thread via cfe-commits

yonghong-song wrote:

Just updated a new revision. Mostly change the offset of r12 based on load and 
store. The new offset tries to make it easy for jit.

https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-04-06 Thread via cfe-commits

https://github.com/yonghong-song edited 
https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-03-30 Thread Jose E. Marchesi via cfe-commits

jemarch wrote:


Hi Yonghong.

As you mention there are many details to discuss, agree on and document,
like the passing conventions of the differnt data types, but in
principle using an arguments pointer in this fashion makes total sense
to me.

I just filed a GCC BZ to track this work at
https://gcc.gnu.org/PR124698.

I will now prototype this, as sketched, in the GCC BPF backend.

> yonghong-song left a comment (llvm/llvm-project#189060)
>
> cc @jemarch


https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-03-27 Thread via cfe-commits

https://github.com/yonghong-song edited 
https://github.com/llvm/llvm-project/pull/189060
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-03-27 Thread via cfe-commits

https://github.com/yonghong-song updated 
https://github.com/llvm/llvm-project/pull/189060

>From 35a32305e5b428fa220bbf4534c8353d3a2eb35e Mon Sep 17 00:00:00 2001
From: Yonghong Song 
Date: Wed, 18 Mar 2026 13:29:09 -0700
Subject: [PATCH] [BPF] Support Stack Arguments

Currently, bpf program and kfunc only support 5 register parameters.
As bpf community and use cases keep expanding, there are some need
to extend 5 register parameters by allocating additional parameters
on stack. There are two main use cases here:
  1. Currently kfunc is limited to 5 register parameters. In some
 special situation, people may want to have more than 5
 parameters. One of example is for sched_ext.
  2. Allowing more stack parameters can make bpf prog writer easier
 since they do not need to carefully limit the number of
 parameters for their programs.

The following is the high-level design:
  - Use bpf register R12 as the frame pointer to stack parameters.
This is to avoid mixing stacks due to R10.
  - Stack parameters must be after 5 register parameters.
  - All parameters should be at most 16 bytes as ByVal parameters
are not supported.
  - Support for cpu v1 to v4 so all cpu versions can use this.
A feature macro __BPF_FEATURE_STACK_ARGUMENT is defined
and users can check whether stack argument is supported or not.

The below is a simple asm code example about stack parameters:

  bar:
/* Retrieve two parameters from the caller of bar(). */
rX = *(u64 *)(r12 - 8)
rY = *(u64 *)(r12 - 16)
...
/* Prepare the single stack parameters for foo1 */
*(u64 *)(r12 - 24) = rZ
call foo1
...
/* Prepare the single stack parameters for foo2 */
*(u64 *)(r12 - 24) = rX
*(u64 *)(r12 - 32) = rY
call foo2
...
  foo1:
/* Retrieve parameter '*(u64 *)(r12 - 24) = rZ' from bar(),
 * and assign the value rZ to rX.
 */
rX = *(u64 *)(r12 - 8)
...
  foo2:
/* Retrieve parameters '*(u64 *)(r12 - 24/32) = rZ' from bar(),
 * and assign values rX/rY to rU/rV.
 */
rU = *(u64 *)(r12 - 8)
rV = *(u64 *)(r12 - 16)
...

The special handling of r12 will be in kernel bpf jit, which will
actually allocate space for stack parameters. For example, for function
bar(), jit could allocate 16 byte stack parameter space to cover
stores for 'r12 - {24,32}' (maximum between foo1 and foo2). The
foo1() and foo2() can retrieve values from caller allocated
parameter space.
   bar (*(u64 *)(r12 - 24) = rZ) -> foo1 (rX = *(u64 *)(r12 - 8))
   bar (*(u64 *)(r12 - 24) = rX) -> foo2 (rU = *(u64 *)(r12 - 8))
   bar (*(u64 *)(r12 - 32) = rY) -> foo2 (rV = *(u64 *)(r12 - 16))

Internally in bpf backend, pseudo insns are generated for
load_stack_arg and store_stack_arg. The BPFMIPeephole pass
changes pseudo insns into proper real bpf insns like the above.
---
 clang/lib/Basic/Targets/BPF.cpp   |   1 +
 .../test/Preprocessor/bpf-predefined-macros.c |   8 +
 llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp   |  32 +++
 llvm/lib/Target/BPF/BPFISelLowering.cpp   | 123 ---
 llvm/lib/Target/BPF/BPFInstrInfo.td   |  32 +++
 llvm/lib/Target/BPF/BPFMIPeephole.cpp |  60 ++
 llvm/lib/Target/BPF/BPFMachineFunctionInfo.h  |  20 ++
 llvm/lib/Target/BPF/BPFRegisterInfo.cpp   |   1 +
 llvm/lib/Target/BPF/BPFRegisterInfo.td|   4 +-
 llvm/lib/Target/BPF/BPFTargetMachine.cpp  |   8 +
 llvm/lib/Target/BPF/BPFTargetMachine.h|   4 +
 .../BPF/Disassembler/BPFDisassembler.cpp  |  14 +-
 llvm/test/CodeGen/BPF/many_args1.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args2.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args3.ll   | 199 ++
 llvm/test/CodeGen/BPF/many_args4.ll   |  65 ++
 llvm/test/CodeGen/BPF/many_args5.ll   |  27 +++
 llvm/test/CodeGen/BPF/many_args6.ll   |  22 ++
 llvm/test/CodeGen/BPF/many_args7.ll   |  23 ++
 llvm/test/CodeGen/BPF/many_args8.ll   |  36 
 20 files changed, 644 insertions(+), 47 deletions(-)
 create mode 100644 llvm/lib/Target/BPF/BPFMachineFunctionInfo.h
 create mode 100644 llvm/test/CodeGen/BPF/many_args3.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args4.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args5.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args6.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args7.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args8.ll

diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp
index 8de1083d758c7..100769ea4cdb1 100644
--- a/clang/lib/Basic/Targets/BPF.cpp
+++ b/clang/lib/Basic/Targets/BPF.cpp
@@ -46,6 +46,7 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
   Builder.defineMacro("__BPF_FEATURE_ADDR_SPACE_CAST");
   Builder.defineMacro("__BPF_FEATURE_MAY_GOTO");
   Builder.defineMacro("__BPF_FEATURE_ATOMIC_MEM_ORDERING");
+  Builder.defineMacro("__BPF_FEATURE_STACK_ARGUMENT");
 
   if (CPU.empty())
 

[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-03-27 Thread via cfe-commits

https://github.com/yonghong-song updated 
https://github.com/llvm/llvm-project/pull/189060

>From 2f7e28bc4b53c536615cbf791d355be69e40865f Mon Sep 17 00:00:00 2001
From: Yonghong Song 
Date: Wed, 18 Mar 2026 13:29:09 -0700
Subject: [PATCH] [BPF] Support Stack Arguments

Currently, bpf program and kfunc only support 5 register parameters.
As bpf community and use cases keep expanding, there are some need
to extend 5 register parameters by allocating additional parameters
on stack. There are two main use cases here:
  1. Currently kfunc is limited to 5 register parameters. In some
 special situation, people may want to have more than 5
 parameters. One of example is for sched_ext.
  2. Allowing more stack parameters can make bpf prog writer easier
 since they do not need to carefully limit the number of
 parameters for their programs.

The following is the high-level design:
  - Use bpf register R12 as the frame pointer to stack parameters.
This is to avoid mixing stacks due to R10.
  - Stack parameters must be after 5 register parameters.
  - All parameters should be at most 16 bytes as ByVal parameters
are not supported.
  - Support for cpu v1 to v4 so all cpu versions can use this.
A feature macro __BPF_FEATURE_STACK_ARGUMENT is defined
and users can check whether stack argument is supported or not.

The below is a simple asm code example about stack parameters:

  bar:
/* Retrieve two parameters from the caller of bar(). */
rX = *(u64 *)(r12 - 8)
rY = *(u64 *)(r12 - 16)
...
/* Prepare the single stack parameters for foo1 */
*(u64 *)(r12 - 24) = rZ
call foo1
...
/* Prepare the single stack parameters for foo2 */
*(u64 *)(r12 - 24) = rX
*(u64 *)(r12 - 32) = rY
call foo2
...
  foo1:
/* Retrieve parameter '*(u64 *)(r12 - 24) = rZ' from bar(),
 * and assign the value rZ to rX.
 */
rX = *(u64 *)(r12 - 8)
...
  foo2:
/* Retrieve parameters '*(u64 *)(r12 - 24/32) = rZ' from bar(),
 * and assign values rX/rY to rU/rV.
 */
rU = *(u64 *)(r12 - 8)
rV = *(u64 *)(r12 - 16)
...

The special handling of r12 will be in kernel bpf jit, which will
actually allocate space for stack parameters. For example, for function
bar(), jit could allocate 16 byte stack parameter space to cover
stores for 'r12 - {24,32}' (maximum between foo1 and foo2). The
foo1() and foo2() can retrieve values from caller allocated
parameter space.
   bar (*(u64 *)(r12 - 24) = rZ) -> foo1 (rX = *(u64 *)(r12 - 8))
   bar (*(u64 *)(r12 - 24) = rX) -> foo2 (rU = *(u64 *)(r12 - 8))
   bar (*(u64 *)(r12 - 32) = rY) -> foo2 (rV = *(u64 *)(r12 - 16))

Internally in bpf backend, pseudo insns are generated for
load_stack_arg and store_stack_arg. The BPFMIPeephole pass
changes pseudo insns into proper real bpf insns like the above.
---
 clang/lib/Basic/Targets/BPF.cpp   |   1 +
 .../test/Preprocessor/bpf-predefined-macros.c |   8 +
 llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp   |  32 +++
 llvm/lib/Target/BPF/BPFISelLowering.cpp   | 123 ---
 llvm/lib/Target/BPF/BPFInstrInfo.td   |  32 +++
 llvm/lib/Target/BPF/BPFMIPeephole.cpp |  60 ++
 llvm/lib/Target/BPF/BPFMachineFunctionInfo.h  |  20 ++
 llvm/lib/Target/BPF/BPFRegisterInfo.cpp   |   1 +
 llvm/lib/Target/BPF/BPFRegisterInfo.td|   4 +-
 llvm/lib/Target/BPF/BPFTargetMachine.cpp  |   8 +
 llvm/lib/Target/BPF/BPFTargetMachine.h|   4 +
 .../BPF/Disassembler/BPFDisassembler.cpp  |  14 +-
 llvm/test/CodeGen/BPF/many_args1.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args2.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args3.ll   | 199 ++
 llvm/test/CodeGen/BPF/many_args4.ll   |  65 ++
 llvm/test/CodeGen/BPF/many_args5.ll   |  22 ++
 llvm/test/CodeGen/BPF/many_args6.ll   |  23 ++
 llvm/test/CodeGen/BPF/many_args7.ll   |  36 
 19 files changed, 617 insertions(+), 47 deletions(-)
 create mode 100644 llvm/lib/Target/BPF/BPFMachineFunctionInfo.h
 create mode 100644 llvm/test/CodeGen/BPF/many_args3.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args4.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args5.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args6.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args7.ll

diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp
index 8de1083d758c7..100769ea4cdb1 100644
--- a/clang/lib/Basic/Targets/BPF.cpp
+++ b/clang/lib/Basic/Targets/BPF.cpp
@@ -46,6 +46,7 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
   Builder.defineMacro("__BPF_FEATURE_ADDR_SPACE_CAST");
   Builder.defineMacro("__BPF_FEATURE_MAY_GOTO");
   Builder.defineMacro("__BPF_FEATURE_ATOMIC_MEM_ORDERING");
+  Builder.defineMacro("__BPF_FEATURE_STACK_ARGUMENT");
 
   if (CPU.empty())
 CPU = "v3";
diff --git a/clang/test/Preprocessor/bpf-predefined-macros.c 

[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-03-27 Thread via cfe-commits

https://github.com/yonghong-song updated 
https://github.com/llvm/llvm-project/pull/189060

>From d743d11360fd18ea283d751c084a1b0232f358dc Mon Sep 17 00:00:00 2001
From: Yonghong Song 
Date: Wed, 18 Mar 2026 13:29:09 -0700
Subject: [PATCH] [BPF] Support Stack Arguments

Currently, bpf program and kfunc only support 5 register parameters.
As bpf community and use cases keep expanding, there are some need
to extend 5 register parameters by allocating additional parameters
on stack. There are two main use cases here:
  1. Currently kfunc is limited to 5 register parameters. In some
 special situation, people may want to have more than 5
 parameters. One of example is for sched_ext.
  2. Allowing more stack parameters can make bpf prog writer easier
 since they do not need to carefully limit the number of
 parameters for their programs.

The following is the high-level design:
  - Use bpf register R12 as the frame pointer to stack parameters.
This is to avoid mixing stacks due to R10.
  - Stack parameters must be after 5 register parameters.
  - All parameters should be at most 16 bytes as ByVal parameters
are not supported.
  - Support for cpu v1 to v4 so all cpu versions can use this.
A feature macro __BPF_FEATURE_STACK_ARGUMENT is defined
and users can check whether stack argument is supported or not.

The below is a simple asm code example about stack parameters:

  bar:
/* Retrieve two parameters from the caller of bar(). */
rX = *(u64 *)(r12 - 8)
rY = *(u64 *)(r12 - 16)
...
/* Prepare the single stack parameters for foo1 */
*(u64 *)(r12 - 24) = rZ
call foo1
...
/* Prepare the single stack parameters for foo2 */
*(u64 *)(r12 - 24) = rX
*(u64 *)(r12 - 32) = rY
call foo2
...
  foo1:
/* Retrieve parameter '*(u64 *)(r12 - 24) = rZ' from bar(),
 * and assign the value rZ to rX.
 */
rX = *(u64 *)(r12 - 8)
...
  foo2:
/* Retrieve parameters '*(u64 *)(r12 - 24/32) = rZ' from bar(),
 * and assign values rX/rY to rU/rV.
 */
rU = *(u64 *)(r12 - 8)
rV = *(u64 *)(r12 - 16)
...

The special handling of r12 will be in kernel bpf jit, which will
actually allocate space for stack parameters. For example, for function
bar(), jit could allocate 16 byte stack parameter space to cover
stores for 'r12 - {24,32}' (maximum between foo1 and foo2). The
foo1() and foo2() can retrieve values from caller allocated
parameter space.
   bar (*(u64 *)(r12 - 24) = rZ) -> foo1 (rX = *(u64 *)(r12 - 8))
   bar (*(u64 *)(r12 - 24) = rX) -> foo2 (rU = *(u64 *)(r12 - 8))
   bar (*(u64 *)(r12 - 32) = rY) -> foo2 (rV = *(u64 *)(r12 - 16))

Internally in bpf backend, pseudo insns are generated for
load_stack_arg and store_stack_arg. The BPFMIPeephole pass
changes pseudo insns into proper real bpf insns like the above.
---
 clang/lib/Basic/Targets/BPF.cpp   |   1 +
 .../test/Preprocessor/bpf-predefined-macros.c |   8 +
 llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp   |  32 +++
 llvm/lib/Target/BPF/BPFISelLowering.cpp   | 118 ---
 llvm/lib/Target/BPF/BPFInstrInfo.td   |  32 +++
 llvm/lib/Target/BPF/BPFMIPeephole.cpp |  60 ++
 llvm/lib/Target/BPF/BPFMachineFunctionInfo.h  |  20 ++
 llvm/lib/Target/BPF/BPFRegisterInfo.cpp   |   1 +
 llvm/lib/Target/BPF/BPFRegisterInfo.td|   4 +-
 llvm/lib/Target/BPF/BPFTargetMachine.cpp  |   8 +
 llvm/lib/Target/BPF/BPFTargetMachine.h|   4 +
 .../BPF/Disassembler/BPFDisassembler.cpp  |  14 +-
 llvm/test/CodeGen/BPF/many_args1.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args2.ll   |   6 +-
 llvm/test/CodeGen/BPF/many_args3.ll   | 196 ++
 llvm/test/CodeGen/BPF/many_args4.ll   |  62 ++
 llvm/test/CodeGen/BPF/many_args5.ll   |  22 ++
 llvm/test/CodeGen/BPF/many_args6.ll   |  23 ++
 llvm/test/CodeGen/BPF/many_args7.ll   |  36 
 19 files changed, 606 insertions(+), 47 deletions(-)
 create mode 100644 llvm/lib/Target/BPF/BPFMachineFunctionInfo.h
 create mode 100644 llvm/test/CodeGen/BPF/many_args3.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args4.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args5.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args6.ll
 create mode 100644 llvm/test/CodeGen/BPF/many_args7.ll

diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp
index 8de1083d758c7..100769ea4cdb1 100644
--- a/clang/lib/Basic/Targets/BPF.cpp
+++ b/clang/lib/Basic/Targets/BPF.cpp
@@ -46,6 +46,7 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
   Builder.defineMacro("__BPF_FEATURE_ADDR_SPACE_CAST");
   Builder.defineMacro("__BPF_FEATURE_MAY_GOTO");
   Builder.defineMacro("__BPF_FEATURE_ATOMIC_MEM_ORDERING");
+  Builder.defineMacro("__BPF_FEATURE_STACK_ARGUMENT");
 
   if (CPU.empty())
 CPU = "v3";
diff --git a/clang/test/Preprocessor/bpf-predefined-macros.c 

[clang] [llvm] [BPF] Support Stack Arguments (PR #189060)

2026-03-27 Thread via cfe-commits

https://github.com/yonghong-song created 
https://github.com/llvm/llvm-project/pull/189060

Currently, bpf program and kfunc only support 5 register parameters. As bpf 
community and use cases keep expanding, there are some need to extend 5 
register parameters by allocating additional parameters on stack. There are two 
main use cases here:
  1. Currently kfunc is limited to 5 register parameters. In some special 
situation, people may want to have more than 5 parameters. One of example is 
for sched_ext.
  2. Allowing more stack parameters can make bpf prog writer easier since they 
do not need to carefully limit the number of parameters for their programs.

The following is the high-level design:
  - Use bpf register R12 as the frame pointer to stack parameters. This is to 
avoid mixing stacks due to R10.
  - Stack parameters must be after 5 register parameters.
  - All parameters should be at most 16 bytes as ByVal parameters are not 
supported.
  - Support for cpu v1 to v4 so all cpu versions can use this. A feature macro 
__BPF_FEATURE_STACK_ARGUMENT is defined and users can check whether stack 
argument is supported or not.

The below is a simple asm code example about stack parameters:
```
  bar:
/* Retrieve two parameters from the caller of bar(). */
rX = *(u64 *)(r12 - 8)
rY = *(u64 *)(r12 - 16)
...
/* Prepare the single stack parameters for foo1 */
*(u64 *)(r12 - 24) = rZ
call foo1
...
/* Prepare the single stack parameters for foo2 */
*(u64 *)(r12 - 24) = rX
*(u64 *)(r12 - 32) = rY
call foo2
...
  foo1:
/* Retrieve parameter '*(u64 *)(r12 - 24) = rZ' from bar(),
 * and assign the value rZ to rX.
 */
rX = *(u64 *)(r12 - 8)
...
  foo2: 
   /* Retrieve parameters '*(u64 *)(r12 - 24/32) = rZ' from bar(),
 * and assign values rX/rY to rU/rV.
 */
   rU = *(u64 *)(r12 - 8)
   rV = *(u64 *)(r12 - 16)
   ...
```
The special handling of r12 will be in kernel bpf jit, which will actually 
allocate space for stack parameters. For example, for function bar(), jit could 
allocate 16 byte stack parameter space to cover stores for 'r12 - {24,32}' 
(maximum between foo1 and foo2). The foo1() and foo2() can retrieve values from 
caller allocated parameter space.
```
   bar (*(u64 *)(r12 - 24) = rZ) -> foo1 (rX = *(u64 *)(r12 - 8))
   bar (*(u64 *)(r12 - 24) = rX) -> foo2 (rU = *(u64 *)(r12 - 8))
   bar (*(u64 *)(r12 - 32) = rY) -> foo2 (rV = *(u64 *)(r12 - 16))
```
Internally in bpf backend, pseudo insns are generated for load_stack_arg and 
store_stack_arg. The BPFMIPeephole pass changes pseudo insns into proper real 
bpf insns like the above.

>From 675157b71e7cb7ce75e29683f3c188e866727e41 Mon Sep 17 00:00:00 2001
From: Yonghong Song 
Date: Wed, 18 Mar 2026 13:29:09 -0700
Subject: [PATCH] [BPF] Support Stack Arguments

Currently, bpf program and kfunc only support 5 register parameters.
As bpf community and use cases keep expanding, there are some need
to extend 5 register parameters by allocating additional parameters
on stack. There are two main use cases here:
  1. Currently kfunc is limited to 5 register parameters. In some
 special situation, people may want to have more than 5
 parameters. One of example is for sched_ext.
  2. Allowing more stack parameters can make bpf prog writer easier
 since they do not need to carefully limit the number of
 parameters for their programs.

The following is the high-level design:
  - Use bpf register R12 as the frame pointer to stack parameters.
This is to avoid mixing stacks due to R10.
  - Stack parameters must be after 5 register parameters.
  - All parameters should be at most 16 bytes as ByVal parameters
are not supported.
  - Support for cpu v1 to v4 so all cpu versions can use this.
A feature macro __BPF_FEATURE_STACK_ARGUMENT is defined
and users can check whether stack argument is supported or not.

The below is a simple asm code example about stack parameters:

  bar:
/* Retrieve two parameters from the caller of bar(). */
rX = *(u64 *)(r12 - 8)
rY = *(u64 *)(r12 - 16)
...
/* Prepare the single stack parameters for foo1 */
*(u64 *)(r12 - 24) = rZ
call foo1
...
/* Prepare the single stack parameters for foo2 */
*(u64 *)(r12 - 24) = rX
*(u64 *)(r12 - 32) = rY
call foo2
...
  foo1:
/* Retrieve parameter '*(u64 *)(r12 - 24) = rZ' from bar(),
 * and assign the value rZ to rX.
 */
rX = *(u64 *)(r12 - 8)
...
  foo2:
/* Retrieve parameters '*(u64 *)(r12 - 24/32) = rZ' from bar(),
 * and assign values rX/rY to rU/rV.
 */
rU = *(u64 *)(r12 - 8)
rV = *(u64 *)(r12 - 16)
...

The special handling of r12 will be in kernel bpf jit, which will
actually allocate space for stack parameters. For example, for function
bar(), jit could allocate 16 byte stack parameter space to cover
stores for 'r12 - {24,32}' (maximum between foo1 and foo2). The
foo1() and foo2() can