public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug target/106733] New: bpf: facilitate constant propagation of function addresses
@ 2022-08-24 13:22 jose.marchesi at oracle dot com
  2022-08-24 13:26 ` [Bug target/106733] " cvs-commit at gcc dot gnu.org
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: jose.marchesi at oracle dot com @ 2022-08-24 13:22 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106733

            Bug ID: 106733
           Summary: bpf: facilitate constant propagation of function
                    addresses
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jose.marchesi at oracle dot com
  Target Milestone: ---

eBPF effectively supports two kind of call instructions:

- The so called pseudo-calls ("bpf to bpf").
- External calls ("bpf to kernel").

The BPF call instruction always gets an immediate argument, whose
interpretation varies depending on the purpose of the instruction:

- For pseudo-calls, the immediate argument is interpreted as a
  32-bit PC-relative displacement measured in number of 64-bit words
  minus one.

- For external calls, the immediate argument is interpreted as the
  identification of a kernel helper.

In order to differenciate both flavors of CALL instructions the SRC
field of the instruction (otherwise unused) is abused as an opcode;
if the field holds 0 the instruction is an external call, if it holds
BPF_PSEUDO_CALL the instruction is a pseudo-call.

C-to-BPF toolchains, including the GNU toolchain, use the following
practical heuristic at assembly time in order to determine what kind
of CALL instruction to generate: call instructions requiring a fixup
at assembly time are interpreted as pseudo-calls.  This means that in
practice a call instruction involving symbols at assembly time (such
as `call foo') is assembled into a pseudo-call instruction, whereas
something like `call 12' is assembled into an external call
instruction.

In both cases, the argument of CALL is an immediate: at the time of
writing eBPF lacks support for indirect calls, i.e. there is no
call-to-register instruction.

This is the reason why BPF programs, in practice, rely on certain
optimizations to happen in order to generate calls to immediates.
This is a typical example involving a kernel helper:

  static void * (*bpf_map_lookup_elem)(void *map, const void *key
        = (void *) 1;

  int foo (...)
  {
    char *ret;

    ret = bpf_map_lookup_elem (args...);
    if (ret)
      return 1;
    return 0;
  }

Note how the code above relies on the compiler to do constant
propagation so the call to bpf_map_lookup_elem can be compiled to a
`call 1' instruction.

While GCC provides a kernel_helper function declaration attribute that
can be used in a robust way to tell GCC to generate an external call
despite of optimization level and any other consideration, the Linux
kernel bpf_helpers.h file relies on tricks like the above.

The BPF backend is currently causing the expander to "undo" SSA constant
propagations like the above by loading function addresses into registers.  This
makes code like the above to not compile properly even with optimization levels
of O2 or more.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Bug target/106733] bpf: facilitate constant propagation of function addresses
  2022-08-24 13:22 [Bug target/106733] New: bpf: facilitate constant propagation of function addresses jose.marchesi at oracle dot com
@ 2022-08-24 13:26 ` cvs-commit at gcc dot gnu.org
  2022-08-24 13:28 ` jose.marchesi at oracle dot com
  2022-08-24 13:28 ` jose.marchesi at oracle dot com
  2 siblings, 0 replies; 4+ messages in thread
From: cvs-commit at gcc dot gnu.org @ 2022-08-24 13:26 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106733

--- Comment #1 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jose E. Marchesi <jemarch@gcc.gnu.org>:

https://gcc.gnu.org/g:6d1f144b3e6e3761375bea657718f58fb720fb44

commit r13-2173-g6d1f144b3e6e3761375bea657718f58fb720fb44
Author: Jose E. Marchesi <jose.marchesi@oracle.com>
Date:   Wed Aug 24 13:07:57 2022 +0200

    bpf: facilitate constant propagation of function addresses

    eBPF effectively supports two kind of call instructions:

    - The so called pseudo-calls ("bpf to bpf").
    - External calls ("bpf to kernel").

    The BPF call instruction always gets an immediate argument, whose
    interpretation varies depending on the purpose of the instruction:

    - For pseudo-calls, the immediate argument is interpreted as a
      32-bit PC-relative displacement measured in number of 64-bit words
      minus one.

    - For external calls, the immediate argument is interpreted as the
      identification of a kernel helper.

    In order to differenciate both flavors of CALL instructions the SRC
    field of the instruction (otherwise unused) is abused as an opcode;
    if the field holds 0 the instruction is an external call, if it holds
    BPF_PSEUDO_CALL the instruction is a pseudo-call.

    C-to-BPF toolchains, including the GNU toolchain, use the following
    practical heuristic at assembly time in order to determine what kind
    of CALL instruction to generate: call instructions requiring a fixup
    at assembly time are interpreted as pseudo-calls.  This means that in
    practice a call instruction involving symbols at assembly time (such
    as `call foo') is assembled into a pseudo-call instruction, whereas
    something like `call 12' is assembled into an external call
    instruction.

    In both cases, the argument of CALL is an immediate: at the time of
    writing eBPF lacks support for indirect calls, i.e. there is no
    call-to-register instruction.

    This is the reason why BPF programs, in practice, rely on certain
    optimizations to happen in order to generate calls to immediates.
    This is a typical example involving a kernel helper:

      static void * (*bpf_map_lookup_elem)(void *map, const void *key)
        = (void *) 1;

      int foo (...)
      {
        char *ret;

        ret = bpf_map_lookup_elem (args...);
        if (ret)
          return 1;
        return 0;
      }

    Note how the code above relies on the compiler to do constant
    propagation so the call to bpf_map_lookup_elem can be compiled to a
    `call 1' instruction.

    While GCC provides a kernel_helper function declaration attribute that
    can be used in a robust way to tell GCC to generate an external call
    despite of optimization level and any other consideration, the Linux
    kernel bpf_helpers.h file relies on tricks like the above.

    This patch modifies the BPF backend to avoid SSA sparse constant
    propagation to be "undone" by the expander loading the function
    address into a register.  A new test is also added.

    Tested in bpf-unknown-linux-gnu.
    No regressions.

    gcc/ChangeLog:

            PR target/106733
            * config/bpf/bpf.cc (bpf_legitimate_address_p): Recognize integer
            constants as legitimate addresses for functions.
            (bpf_small_register_classes_for_mode_p): Define target hook.

    gcc/testsuite/ChangeLog:

            PR target/106733
            * gcc.target/bpf/constant-calls.c: Rename to ...
            * gcc.target/bpf/constant-calls-1.c: and modify to not expect
            failure anymore.
            * gcc.target/bpf/constant-calls-2.c: New test.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Bug target/106733] bpf: facilitate constant propagation of function addresses
  2022-08-24 13:22 [Bug target/106733] New: bpf: facilitate constant propagation of function addresses jose.marchesi at oracle dot com
  2022-08-24 13:26 ` [Bug target/106733] " cvs-commit at gcc dot gnu.org
@ 2022-08-24 13:28 ` jose.marchesi at oracle dot com
  2022-08-24 13:28 ` jose.marchesi at oracle dot com
  2 siblings, 0 replies; 4+ messages in thread
From: jose.marchesi at oracle dot com @ 2022-08-24 13:28 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106733

--- Comment #2 from Jose E. Marchesi <jose.marchesi at oracle dot com> ---
Urgh I obviously meant bpf-unknown-none.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Bug target/106733] bpf: facilitate constant propagation of function addresses
  2022-08-24 13:22 [Bug target/106733] New: bpf: facilitate constant propagation of function addresses jose.marchesi at oracle dot com
  2022-08-24 13:26 ` [Bug target/106733] " cvs-commit at gcc dot gnu.org
  2022-08-24 13:28 ` jose.marchesi at oracle dot com
@ 2022-08-24 13:28 ` jose.marchesi at oracle dot com
  2 siblings, 0 replies; 4+ messages in thread
From: jose.marchesi at oracle dot com @ 2022-08-24 13:28 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106733

Jose E. Marchesi <jose.marchesi at oracle dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|---                         |FIXED
             Status|UNCONFIRMED                 |RESOLVED

--- Comment #3 from Jose E. Marchesi <jose.marchesi at oracle dot com> ---
Changing status to fixed.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-08-24 13:28 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-24 13:22 [Bug target/106733] New: bpf: facilitate constant propagation of function addresses jose.marchesi at oracle dot com
2022-08-24 13:26 ` [Bug target/106733] " cvs-commit at gcc dot gnu.org
2022-08-24 13:28 ` jose.marchesi at oracle dot com
2022-08-24 13:28 ` jose.marchesi at oracle dot com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).