llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.13k stars 12.01k forks source link

bpf target, preserve_access_index gives useless bitshifts #59908

Open socketpair opened 1 year ago

socketpair commented 1 year ago

https://godbolt.org/z/ProhnxfTv

-target bpf -mcpu=v2 -O3

typedef unsigned int __u32;
typedef long long unsigned int __u64;

#pragma clang attribute push(__attribute__((preserve_access_index)), \
                                 apply_to = record)
struct iphdr {
    __u32 protocol;
    __u32 daddr;
};
#pragma clang attribute pop

int some_fun(const struct iphdr* ip) {
    const __u64 dst_ip = ip->daddr;  // note __u64 variable

    if (ip->protocol) __asm__("" ::: "memory");

    // only if: __asm__ present, -mcpu=v{1,2} -O3 and preserve_access_index
    return dst_ip == 11223344ull;
}

int some_fun_2(const struct iphdr* ip) {
    const __u64 dst_ip = ip->daddr;  // note __u64 variable
    return dst_ip == 11223344ull;
}

// no preserve_access_index
struct iphdr2 {
    __u32 protocol;
    __u32 daddr;
};

int some_fun_3(const struct iphdr2* ip) {
    const __u64 dst_ip = ip->daddr; // note __u64 variable

    if (ip->protocol) __asm__("" ::: "memory");

    return dst_ip == 11223344ull;
}
some_fun:                               # @some_fun
        r2 = *(u32 *)(r1 + 4)
        r1 = *(u32 *)(r1 + 0)
        if r1 == 0 goto LBB0_2 ;--------useless conditional jump (that's another issue?)
LBB0_2:
        ; ---------------------------------------------- WHAT's this ?!
        r2 <<= 32
        r2 >>= 32
        if r2 == 11223344 goto LBB0_4
LBB0_4:
        exit
; ######################
some_fun_2:                             # @some_fun_2
        r1 = *(u32 *)(r1 + 4)
        if r1 == 11223344 goto LBB1_2  ; --------------- no shifts here
LBB1_2:
        exit
; ######################
some_fun_3:                             # @some_fun_3
        r2 = *(u32 *)(r1 + 4)
        r1 = *(u32 *)(r1 + 0)
        if r1 == 0 goto LBB2_2
LBB2_2:
        r1 = r2
        if r1 == 11223344 goto LBB2_4  ; --------------- no shifts here
LBB2_4:
        exit
eddyz87 commented 9 months ago

I think this was fixed by the following commit: 651e644595b72c22fd22f51358cf083146790ed4 The <<= >>= pair is zero extension, before that commit compiler was not aware that zero extension of 32-bit load is always free. The empty jump is an artifact of inline assembly usage: if (ip->protocol) __asm__("" ::: "memory");:

The example as compiled by current clang:

$ clang --target=bpf -mcpu=v2 -O2 t.c -c -o - | llvm-objdump --no-show-raw-insn -d -

<stdin>:    file format elf64-bpf

Disassembly of section .text:

0000000000000000 <some_fun>:
       0:   r2 = *(u32 *)(r1 + 0x4)
       1:   r1 = *(u32 *)(r1 + 0x0)
       2:   if r1 == 0x0 goto +0x0 <LBB0_2>

0000000000000018 <LBB0_2>:
       3:   r0 = 0x1
       4:   if r2 == 0xab4130 goto +0x1 <LBB0_4>
       5:   r0 = 0x0

0000000000000030 <LBB0_4>:
       6:   exit

0000000000000038 <some_fun_2>:
       7:   r1 = *(u32 *)(r1 + 0x4)
       8:   r0 = 0x1
       9:   if r1 == 0xab4130 goto +0x1 <LBB1_2>
      10:   r0 = 0x0

0000000000000058 <LBB1_2>:
      11:   exit

0000000000000060 <some_fun_3>:
      12:   r2 = *(u32 *)(r1 + 0x4)
      13:   r1 = *(u32 *)(r1 + 0x0)
      14:   if r1 == 0x0 goto +0x0 <LBB2_2>

0000000000000078 <LBB2_2>:
      15:   r0 = 0x1
      16:   if r2 == 0xab4130 goto +0x1 <LBB2_4>
      17:   r0 = 0x0

0000000000000090 <LBB2_4>:
      18:   exit