Clang incorrectly optimizing out for conditional in Linux kernel

Hi,

I am trying to get the Linux kernel to compile and boot using clang. The code compiles fine, but the kernel does not boot. It looks like the following macro in mm/vmalloc.c (line 650) is optimizing out the exit condition on the for loop:

#define llist_for_each_entry(pos, node, member)
for ((pos) = llist_entry((node), typeof((pos)), member);
&(pos)->member != NULL;
(pos) = llist_entry((pos)->member.next, typeof(
(pos)), member))

Here’s the disassembly:

LLVM 4.0

ffffffff811874c3: 48 87 04 25 60 a0 0e xchg %rax,0xffffffff820ea060
ffffffff811874ca: 82
ffffffff811874cb: eb 07 jmp ffffffff811874d4 <__purge_vmap_area_lazy+0x294>
ffffffff811874cd: 0f 1f 00 nopl (%rax)
ffffffff811874d0: 48 8b 40 40 mov 0x40(%rax),%rax
ffffffff811874d4: 48 83 c0 c0 add $0xffffffffffffffc0,%rax
ffffffff811874d8: 48 8b 08 mov (%rax),%rcx
ffffffff811874db: 49 3b 4d 00 cmp 0x0(%r13),%rcx
ffffffff811874df: 73 04 jae ffffffff811874e5 <__purge_vmap_area_lazy+0x2a5>
ffffffff811874e1: 49 89 4d 00 mov %rcx,0x0(%r13)
ffffffff811874e5: 48 8b 48 08 mov 0x8(%rax),%rcx
ffffffff811874e9: 49 3b 0e cmp (%r14),%rcx
ffffffff811874ec: 76 e2 jbe ffffffff811874d0 <__purge_vmap_area_lazy+0x290>
ffffffff811874ee: 49 89 0e mov %rcx,(%r14)
ffffffff811874f1: eb dd jmp ffffffff811874d0 <__purge_vmap_area_lazy+0x290>

GCC

ffffffff811772d6: 48 87 05 2b e7 f6 00 xchg %rax,0xf6e72b(%rip) # ffffffff820e5a08 <vmap_purge_list>
ffffffff811772dd: 48 8d 58 c0 lea -0x40(%rax),%rbx
ffffffff811772e1: 31 c9 xor %ecx,%ecx
ffffffff811772e3: 48 85 c0 test %rax,%rax # <==== init test
ffffffff811772e6: 48 89 da mov %rbx,%rdx
ffffffff811772e9: 0f 84 31 02 00 00 je ffffffff81177520 <__purge_vmap_area_lazy+0x280>
ffffffff811772ef: 90 nop
ffffffff811772f0: 48 8b 02 mov (%rdx),%rax
ffffffff811772f3: 49 3b 45 00 cmp 0x0(%r13),%rax
ffffffff811772f7: 73 04 jae ffffffff811772fd <__purge_vmap_area_lazy+0x5d>
ffffffff811772f9: 49 89 45 00 mov %rax,0x0(%r13)
ffffffff811772fd: 48 8b 42 08 mov 0x8(%rdx),%rax
ffffffff81177301: 49 3b 06 cmp (%r14),%rax
ffffffff81177304: 76 07 jbe ffffffff8117730d <__purge_vmap_area_lazy+0x6d>
ffffffff81177306: 49 89 06 mov %rax,(%r14)
ffffffff81177309: 48 8b 42 08 mov 0x8(%rdx),%rax
ffffffff8117730d: 48 2b 02 sub (%rdx),%rax
ffffffff81177310: 48 c1 e8 0c shr $0xc,%rax
ffffffff81177314: 01 c1 add %eax,%ecx
ffffffff81177316: 48 8b 42 40 mov 0x40(%rdx),%rax
ffffffff8117731a: 48 85 c0 test %rax,%rax # <==== loop test
ffffffff8117731d: 48 8d 50 c0 lea -0x40(%rax),%rdx
ffffffff81177321: 75 cd jne ffffffff811772f0 <__purge_vmap_area_lazy+0x50>

Hi,

I am trying to get the Linux kernel to compile and boot using clang.
The code compiles fine, but the kernel does not boot. It looks like the
following macro in mm/vmalloc.c (line 650) is optimizing out the exit
condition on the for loop:

#define llist_for_each_entry(pos, node, member) \
    for ((pos) = llist_entry((node), typeof(*(pos)), member); \
         &(pos)->member != NULL;

This comparison is tautologically true because it'd be UB to construct the address if pos were null, and true otherwise.

Jon

         \

         (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))

snip