llvm-project/clang/lib/Basic/Targets
Yonghong Song 05e46979d2 [BPF] do compile-once run-everywhere relocation for bitfields
A bpf specific clang intrinsic is introduced:
   u32 __builtin_preserve_field_info(member_access, info_kind)
Depending on info_kind, different information will
be returned to the program. A relocation is also
recorded for this builtin so that bpf loader can
patch the instruction on the target host.
This clang intrinsic is used to get certain information
to facilitate struct/union member relocations.

The offset relocation is extended by 4 bytes to
include relocation kind.
Currently supported relocation kinds are
 enum {
    FIELD_BYTE_OFFSET = 0,
    FIELD_BYTE_SIZE,
    FIELD_EXISTENCE,
    FIELD_SIGNEDNESS,
    FIELD_LSHIFT_U64,
    FIELD_RSHIFT_U64,
 };
for __builtin_preserve_field_info. The old
access offset relocation is covered by
    FIELD_BYTE_OFFSET = 0.

An example:
struct s {
    int a;
    int b1:9;
    int b2:4;
};
enum {
    FIELD_BYTE_OFFSET = 0,
    FIELD_BYTE_SIZE,
    FIELD_EXISTENCE,
    FIELD_SIGNEDNESS,
    FIELD_LSHIFT_U64,
    FIELD_RSHIFT_U64,
};

void bpf_probe_read(void *, unsigned, const void *);
int field_read(struct s *arg) {
  unsigned long long ull = 0;
  unsigned offset = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_OFFSET);
  unsigned size = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_SIZE);
 #ifdef USE_PROBE_READ
  bpf_probe_read(&ull, size, (const void *)arg + offset);
  unsigned lshift = __builtin_preserve_field_info(arg->b2, FIELD_LSHIFT_U64);
 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
  lshift = lshift + (size << 3) - 64;
 #endif
 #else
  switch(size) {
  case 1:
    ull = *(unsigned char *)((void *)arg + offset); break;
  case 2:
    ull = *(unsigned short *)((void *)arg + offset); break;
  case 4:
    ull = *(unsigned int *)((void *)arg + offset); break;
  case 8:
    ull = *(unsigned long long *)((void *)arg + offset); break;
  }
  unsigned lshift = __builtin_preserve_field_info(arg->b2, FIELD_LSHIFT_U64);
 #endif
  ull <<= lshift;
  if (__builtin_preserve_field_info(arg->b2, FIELD_SIGNEDNESS))
    return (long long)ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64);
  return ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64);
}

There is a minor overhead for bpf_probe_read() on big endian.

The code and relocation generated for field_read where bpf_probe_read() is
used to access argument data on little endian mode:
        r3 = r1
        r1 = 0
        r1 = 4  <=== relocation (FIELD_BYTE_OFFSET)
        r3 += r1
        r1 = r10
        r1 += -8
        r2 = 4  <=== relocation (FIELD_BYTE_SIZE)
        call bpf_probe_read
        r2 = 51 <=== relocation (FIELD_LSHIFT_U64)
        r1 = *(u64 *)(r10 - 8)
        r1 <<= r2
        r2 = 60 <=== relocation (FIELD_RSHIFT_U64)
        r0 = r1
        r0 >>= r2
        r3 = 1  <=== relocation (FIELD_SIGNEDNESS)
        if r3 == 0 goto LBB0_2
        r1 s>>= r2
        r0 = r1
LBB0_2:
        exit

Compare to the above code between relocations FIELD_LSHIFT_U64 and
FIELD_LSHIFT_U64, the code with big endian mode has four more
instructions.
        r1 = 41   <=== relocation (FIELD_LSHIFT_U64)
        r6 += r1
        r6 += -64
        r6 <<= 32
        r6 >>= 32
        r1 = *(u64 *)(r10 - 8)
        r1 <<= r6
        r2 = 60   <=== relocation (FIELD_RSHIFT_U64)

The code and relocation generated when using direct load.
        r2 = 0
        r3 = 4
        r4 = 4
        if r4 s> 3 goto LBB0_3
        if r4 == 1 goto LBB0_5
        if r4 == 2 goto LBB0_6
        goto LBB0_9
LBB0_6:                                 # %sw.bb1
        r1 += r3
        r2 = *(u16 *)(r1 + 0)
        goto LBB0_9
LBB0_3:                                 # %entry
        if r4 == 4 goto LBB0_7
        if r4 == 8 goto LBB0_8
        goto LBB0_9
LBB0_8:                                 # %sw.bb9
        r1 += r3
        r2 = *(u64 *)(r1 + 0)
        goto LBB0_9
LBB0_5:                                 # %sw.bb
        r1 += r3
        r2 = *(u8 *)(r1 + 0)
        goto LBB0_9
LBB0_7:                                 # %sw.bb5
        r1 += r3
        r2 = *(u32 *)(r1 + 0)
LBB0_9:                                 # %sw.epilog
        r1 = 51
        r2 <<= r1
        r1 = 60
        r0 = r2
        r0 >>= r1
        r3 = 1
        if r3 == 0 goto LBB0_11
        r2 s>>= r1
        r0 = r2
LBB0_11:                                # %sw.epilog
        exit

Considering verifier is able to do limited constant
propogation following branches. The following is the
code actually traversed.
        r2 = 0
        r3 = 4   <=== relocation
        r4 = 4   <=== relocation
        if r4 s> 3 goto LBB0_3
LBB0_3:                                 # %entry
        if r4 == 4 goto LBB0_7
LBB0_7:                                 # %sw.bb5
        r1 += r3
        r2 = *(u32 *)(r1 + 0)
LBB0_9:                                 # %sw.epilog
        r1 = 51   <=== relocation
        r2 <<= r1
        r1 = 60   <=== relocation
        r0 = r2
        r0 >>= r1
        r3 = 1
        if r3 == 0 goto LBB0_11
        r2 s>>= r1
        r0 = r2
LBB0_11:                                # %sw.epilog
        exit

For native load case, the load size is calculated to be the
same as the size of load width LLVM otherwise used to load
the value which is then used to extract the bitfield value.

Differential Revision: https://reviews.llvm.org/D67980

llvm-svn: 374099
2019-10-08 18:23:17 +00:00
..
AArch64.cpp Add SVE opaque built-in types 2019-08-09 08:52:54 +00:00
AArch64.h [AArch64] Add support for Transactional Memory Extension (TME) 2019-07-31 12:52:17 +00:00
AMDGPU.cpp AMDGPU: Add builtins for is_shared/is_private 2019-09-05 03:00:43 +00:00
AMDGPU.h [AMDGPU] gfx1010 clang target 2019-05-13 23:15:59 +00:00
ARC.cpp Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
ARC.h Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
ARM.cpp [ARM] Update clang for removal of vfp2d16 and vfp2d16sp 2019-09-17 21:43:19 +00:00
ARM.h [Targets] Move soft-float-abi filtering to `initFeatureMap` 2019-06-14 00:35:17 +00:00
AVR.cpp Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
AVR.h Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
BPF.cpp [BPF] do compile-once run-everywhere relocation for bitfields 2019-10-08 18:23:17 +00:00
BPF.h [BPF] do compile-once run-everywhere relocation for bitfields 2019-10-08 18:23:17 +00:00
Hexagon.cpp Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
Hexagon.h Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
Lanai.cpp Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
Lanai.h Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
Le64.cpp Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
Le64.h Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
MSP430.cpp Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
MSP430.h [MSP430] Ajust f32/f64 alignment according to MSP430 EABI 2019-01-25 08:51:53 +00:00
Mips.cpp [Headers][mips] Add `__attribute__((__mode__(__unwind_word__)))` to the _Unwind_Word / _Unwind_SWord definitions 2019-02-13 18:27:09 +00:00
Mips.h [Headers][mips] Add `__attribute__((__mode__(__unwind_word__)))` to the _Unwind_Word / _Unwind_SWord definitions 2019-02-13 18:27:09 +00:00
NVPTX.cpp [HIP] Add GPU arch gfx1010, gfx1011, and gfx1012 2019-07-11 17:50:09 +00:00
NVPTX.h [DEBUG_INFO][NVPTX] Generate correct data about variable address class. 2019-02-05 19:45:57 +00:00
OSTargets.cpp De-templatize non-dependent VS macro logic, NFC 2019-07-09 20:57:28 +00:00
OSTargets.h Reland "Change the X86 datalayout to add three address spaces 2019-09-10 23:15:38 +00:00
PNaCl.cpp Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
PNaCl.h Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
PPC.cpp Add -m(no)-spe to clang 2019-09-05 13:38:46 +00:00
PPC.h Add -m(no)-spe to clang 2019-09-05 13:38:46 +00:00
RISCV.cpp [RISCV] Define __riscv_cmodel_medlow and __riscv_cmodel_medany correctly 2019-09-17 08:09:56 +00:00
RISCV.h [RISCV] Set MaxAtomicInlineWidth and MaxAtomicPromoteWidth for RV32/RV64 targets with atomics 2019-08-27 15:41:16 +00:00
SPIR.cpp Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
SPIR.h Remove CallingConvMethodType 2019-07-25 17:14:45 +00:00
Sparc.cpp Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
Sparc.h [clang, test] Fix Clang :: Headers/max_align.c on 64-bit SPARC 2019-07-23 16:24:00 +00:00
SystemZ.cpp [SystemZ] Support z15 processor name 2019-09-20 23:06:03 +00:00
SystemZ.h [SystemZ] Add support for new cpu architecture - arch13 2019-07-12 18:14:51 +00:00
TCE.cpp Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
TCE.h Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
WebAssembly.cpp [WebAssembly] Add multivalue and tail-call target features 2019-05-23 17:26:47 +00:00
WebAssembly.h [WebAssembly] Add multivalue and tail-call target features 2019-05-23 17:26:47 +00:00
X86.cpp [X86] Remove what little support we had for MPX 2019-08-29 18:09:02 +00:00
X86.h Reland "Change the X86 datalayout to add three address spaces 2019-09-10 23:15:38 +00:00
XCore.cpp Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00
XCore.h Update the file headers across all of the LLVM projects in the monorepo 2019-01-19 08:50:56 +00:00