Skip to content

BPF ISel crash on LLVM 14 with ctlz / __builtin_clz lowering in ilog2_u32 under -target bpf{el,eb} -mcpu=v1 #158208

@sudhi-vm

Description

@sudhi-vm

Environment

  • LLVM/Clang: Ubuntu clang version 14.0.0-1ubuntu1.1
  • Targets: bpfel and bpfeb
  • Flags: -O2 -mcpu=v1 -target bpf{el,eb}
  • Reproducibility: always, with minimal tc program below

Minimal source (repro.c)

#include <linux/bpf.h>
#include <linux/pkt_cls.h>

#define SEC(NAME) __attribute__((section(NAME), used))
typedef __u32 u32;

static __always_inline u32 ilog2_u32(u32 v) {
    return 31u - __builtin_clz(v | 1u);
}

SEC("tc")
int repro_prog(struct __sk_buff *skb)
{
    u32 x = ilog2_u32((u32)skb->len);
    return x ? TC_ACT_SHOT : TC_ACT_OK;
}

char _license[] SEC("license") = "GPL";

Reproduction steps

Little-endian:

clang -O2 -g -Wall \
  -target bpfel -mcpu=v1 \
  -I/usr/include/x86_64-linux-gnu \
  -c repro.c -o repro_bpfel.o

Big-endian:

clang -O2 -g -Wall \
  -target bpfeb -mcpu=v1 \
  -I/usr/include/x86_64-linux-gnu \
  -c repro.c -o repro_bpfeb.o

Observed result

Clang crashes during code generation:

Code generation
Running pass 'Function Pass Manager' on module 'repro.c'.
Running pass 'BPF DAG->DAG Pattern Instruction Selection' on function '@repro_prog'
#0  llvm::sys::PrintStackTrace
#1  llvm::sys::RunSignalHandlers
#2  llvm::sys::CleanupOnSignal
#3  ...
#5  llvm::SelectionDAG::createOperands
#6  llvm::SelectionDAG::getNode
#7  ... (BPF ISel lowering) ...
#9  llvm::SelectionDAG::Legalize
#11 llvm::SelectionDAGISel::CodeGenAndEmitDAG
...
clang: error: clang frontend command failed with exit code 139

Expected result

  • No crash.
  • Either successful codegen, or a diagnostic if ctlz on v1 is not legal and needs expansion.

Notes / Workarounds

  • Replacing the expression with a branchy ilog2 (no builtins) avoids the crash.
  • Example safe replacement:
    static __always_inline u32 ilog2_u32(u32 v) {
        u32 r = 0; v |= 1;
        if (v >= (1u<<16)) { v >>= 16; r += 16; }
        if (v >= (1u<< 8)) { v >>=  8; r +=  8; }
        if (v >= (1u<< 4)) { v >>=  4; r +=  4; }
        if (v >= (1u<< 2)) { v >>=  2; r +=  2; }
        if (v >= (1u<< 1)) {           r +=  1; }
        return r;
    }
  • The problem is reproducible even with LLVM 18.1.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions