Cc llvmdev: Re: llvm bpf debug info. Re: [RFC PATCH v4 3/3] bpf: Introduce function for outputing data to perf event

Send again since llvmdev is moved to llvm-dev@lists.llvm.org

And for this:

I tried this test function:

void bpf_store_half(void *skb, int off, int val) asm("llvm.bpf.store.half");
int func()
{
         bpf_store_half(0, 0, 0);
         return 0;
}

Compiled with:

$ clang -g -target bpf -O2 -S -c test.c

And get this:

         .text
         .globl func
         .align 8
func: # @func
# BB#0: # %entry
         mov r1, 0
         mov r2, 0
         mov r3, 0
         call llvm.bpf.store.half
         mov r0, 0
         ret

Without -S, it generate a function relocation:

$ objdump -r ./test.o

./test.o: file format elf64-little

RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000018 UNKNOWN llvm.bpf.store.half

It doesn't work as you suggestion. I think we still need to do something
in clang frontend, or it can only be used in '.ll'.

Thank you.

it didn't work because number and types of args were incompatible.
Every samples/bpf/sockex[0-9]_kern.c is using llvm.bpf.load.* intrinsics.

the typeid changing ids with order is surprising.
I think the assertion in ExtractTypeInfo() is not hard.
Just there were no such use cases. May be we can do something
similar to what LowerIntrinsicCall() does and lower it differently
in the backend.

void bpf_store_half(void *skb, int off, int val)
asm("llvm.bpf.store.half");
int func()
{
         bpf_store_half(0, 0, 0);
         return 0;
}

Compiled with:

$ clang -g -target bpf -O2 -S -c test.c

And get this:

         .text
         .globl func
         .align 8
func: # @func
# BB#0: # %entry
         mov r1, 0
         mov r2, 0
         mov r3, 0
         call llvm.bpf.store.half

it didn't work because number and types of args were incompatible.
Every samples/bpf/sockex[0-9]_kern.c is using llvm.bpf.load.* intrinsics.

Make it work. Thank you.

It doesn't work for me at first since in my llvm there's only llvm.bpf.load.*.

I think llvm.bpf.store.* belone to some patches you haven't posted yet?

the typeid changing ids with order is surprising.
I think the assertion in ExtractTypeInfo() is not hard.
Just there were no such use cases. May be we can do something
similar to what LowerIntrinsicCall() does and lower it differently
in the backend.

But in backend can we still get type information? I thought type is
meaningful in frontend only, and backend behaviors is unable to affect
DWARF generation, right?

Thank you.

It doesn't work for me at first since in my llvm there's only
llvm.bpf.load.*.

I think llvm.bpf.store.* belone to some patches you haven't posted yet?

nope. only loads have special instructions ld_abs/ld_ind
which are represented by these intrinsics.
stores, so far, are done via single bpf_store_bytes() helper function.

>the typeid changing ids with order is surprising.
>I think the assertion in ExtractTypeInfo() is not hard.
>Just there were no such use cases. May be we can do something
>similar to what LowerIntrinsicCall() does and lower it differently
>in the backend.
>
But in backend can we still get type information? I thought type is
meaningful in frontend only, and backend behaviors is unable to affect
DWARF generation, right?

why do we need to affect type generation? we just need to know dwarf
type id in the backend, so we can emit it as a constant.
I still think lowering eh_typeid_for differently may work.
Like instead of doing
GV = ExtractTypeInfo(I.getArgOperand(0)) followed by
getMachineFunction().getMMI().getTypeIDFor(GV)
we can get dwarf type id from I.getArgOperand(0) if it's
any pointer to struct type.
I'm not familiar with dwarf handling part of llvm, but feels possible.

It doesn't work for me at first since in my llvm there's only
llvm.bpf.load.*.

I think llvm.bpf.store.* belone to some patches you haven't posted yet?

nope. only loads have special instructions ld_abs/ld_ind
which are represented by these intrinsics.
stores, so far, are done via single bpf_store_bytes() helper function.

the typeid changing ids with order is surprising.
I think the assertion in ExtractTypeInfo() is not hard.
Just there were no such use cases. May be we can do something
similar to what LowerIntrinsicCall() does and lower it differently
in the backend.

But in backend can we still get type information? I thought type is
meaningful in frontend only, and backend behaviors is unable to affect
DWARF generation, right?

why do we need to affect type generation? we just need to know dwarf
type id in the backend, so we can emit it as a constant.
I still think lowering eh_typeid_for differently may work.
Like instead of doing
GV = ExtractTypeInfo(I.getArgOperand(0)) followed by
getMachineFunction().getMMI().getTypeIDFor(GV)
we can get dwarf type id from I.getArgOperand(0) if it's
any pointer to struct type.

I have a bad news to tell:

#include <stdio.h>
struct my_str {
         int x;
         int y;
} __gv_my_str;
struct my_str __gv_my_str_;

struct my_str2 {
         int x;
         int y;
} __gv_my_str2;

int typeid(void *p) asm("llvm.eh.typeid.for");

int main()
{
         printf("%d\n", typeid(&__gv_my_str));
         printf("%d\n", typeid(&__gv_my_str_));
         printf("%d\n", typeid(&__gv_my_str2));
         return 0;
}

Compiled with clang into x86 executable, then:

$ ./a.out
3
2
1

See? I have two types but reported 3 IDs.

And here is the implementation of getTypeIDFor, in lib/CodeGen/MachineModuleInfo.cpp:

unsigned MachineModuleInfo::getTypeIDFor(const GlobalValue *TI) {
   for (unsigned i = 0, N = TypeInfos.size(); i != N; ++i)
     if (TypeInfos[i] == TI) return i + 1;

   TypeInfos.push_back(TI);
   return TypeInfos.size();
}

It only checks value in a stupid way.

Now the dwarf side becomes clear (see my other response), but the frontend may require
totally reconsidering.

Do you know someone in LLVM-dev who can help us?

Thank you.

that's expected. We don't have to use default lowering
of typeid_for with getTypeIDFor. bpf backend specific
lowering can be different, though in this case it's odd
that id for __gv_my_str and __gv_my_str_ are different.
__gv_my_str and __gv_my_str2 should be different.