Hi,

just tested the clang eBPF backend. Very cool thing :)

But I've noticed that the codegen creates really odd things which I
cannot explain from my understanding of the ISA.  My test is attached
and was compiled via:

clang -O2 -target bpf -x c -c ebpf_opimizer_problems.o -o
ebpf_opimizer_problems.o
llvm-objdump -S ebpf_opimizer_problems.o

First thing is the odd way how 8 bit loads to an uint8_t are handled
(see bug1_sec):

      0:       bf 16 00 00 00 00 00 00         r6 = r1
      1:       30 00 00 00 00 00 00 00         r0 = *(u8 *)skb[0]
      2:       57 00 00 00 ff ff 00 00         r0 &= 65535
      3:       95 00 00 00 00 00 00 00         exit

I have no idea why the second instruction (line "2:") would be
required when there was just a load of 8 bit to the 64 bit register.
This isn't generated when it is stored in an uint32_t or uint64_t
variable (but also when storing it in an uint16_t). This can be seen
in ok1_sec, ok1_too_a_sec and ok1_too_b_sec.

The other problem is the chaining of tests which results in an extra
store for the temporary output register (r7, see bug2_sec):

      0:       bf 16 00 00 00 00 00 00         r6 = r1
      1:       b7 07 00 00 00 00 00 00         r7 = 0
      2:       30 00 00 00 00 00 00 00         r0 = *(u8 *)skb[0]
      3:       55 00 04 00 01 00 00 00         if r0 != 1 goto 4
      4:       30 00 00 00 01 00 00 00         r0 = *(u8 *)skb[1]
      5:       b7 07 00 00 15 00 00 00         r7 = 21
      6:       15 00 01 00 01 00 00 00         if r0 == 1 goto 1
      7:       b7 07 00 00 00 00 00 00         r7 = 0

LBB4_3:
      8:       bf 70 00 00 00 00 00 00         r0 = r7
      9:       95 00 00 00 00 00 00 00         exit

For unknown reasons, the line "6:" was changed from an JNE to an JEQ.
This makes it necessary to introduce link "5:" and line "7:". It would
have been better (in my eyes) to use keep it an JNE, move line "5:"
after the comparison and drop line "7:". This would look like this
(removed the bytecode to make it easier for me):

      0:       r6 = r1
      1:       r7 = 0
      2:       r0 = *(u8 *)skb[0]
      3:       if r0 != 1 goto 3
      4:       r0 = *(u8 *)skb[1]
      5:       if r0 != 1 goto 1
      6:       r7 = 21
LBB4_3:
      7:       r0 = r7
      8:       exit

Or a different version (not so easily readable because it is
asymmetric) would have been:

       0:       bf 16 00 00 00 00 00 00         r6 = r1
      1:       30 00 00 00 00 00 00 00         r0 = *(u8 *)skb[0]
      2:       55 00 03 00 01 00 00 00         if r0 != 1 goto 3
      3:       b7 07 00 00 15 00 00 00         r7 = 21
      4:       30 00 00 00 01 00 00 00         r0 = *(u8 *)skb[1]
      5:       15 00 01 00 01 00 00 00         if r0 == 1 goto 1

LBB4_2:
      6:       b7 07 00 00 00 00 00 00         r7 = 0

LBB4_3:
      7:       bf 70 00 00 00 00 00 00         r0 = r7
      8:       95 00 00 00 00 00 00 00         exit


The used version (Debian buster amd64) is:

clang version 5.0.1-2 (tags/RELEASE_501/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
#include <stddef.h>
#include <stdint.h>

struct __sk_buff;
unsigned long long load_byte(void *skb, unsigned long long off) asm("llvm.bpf.load.byte");


/* FIRST eBPF optimizer "BUG" */

__attribute__((section("bug1_sec"), used))
int bug1(struct __sk_buff *skb)
{
	uint8_t t = load_byte(skb, 0);

	return t;
}

__attribute__((section("ok1_sec"), used))
int ok1(struct __sk_buff *skb)
{
	return load_byte(skb, 0);
}

__attribute__((section("ok1_too_a_sec"), used))
int ok1_too_a(struct __sk_buff *skb)
{
	uint32_t t = load_byte(skb, 0);

	return t;
}

__attribute__((section("ok1_too_b_sec"), used))
int ok1_too_b(struct __sk_buff *skb)
{
	uint64_t t = load_byte(skb, 0);

	return t;
}


/* SECOND eBPF optimizer "BUG" */

__attribute__((section("bug2_sec"), used))
int bug2(struct __sk_buff *skb)
{
	uint64_t t;

	t = load_byte(skb, 0);
	if (t != 1)
		return 0;

	t = load_byte(skb, 1);
	if (t != 1)
		return 0;

	return 21;
}
_______________________________________________
cfe-users mailing list
cfe-users@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-users

Reply via email to