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 <jema...@gcc.gnu.org>:

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

commit r13-2173-g6d1f144b3e6e3761375bea657718f58fb720fb44
Author: Jose E. Marchesi <jose.march...@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.

Reply via email to