https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123963
Bug ID: 123963
Summary: bpf: bpf_core_lower pass generating a large struct
copy hitting -minline-memops-threshold
Product: gcc
Version: 16.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: vineetg at gcc dot gnu.org
Target Milestone: ---
I was trying to build kernel bpf selftests with a libbpf change to emit
attribute preserve_access_index for aggregate types (so generated vmlinux.h has
them).
However one of tests fails to build now
```
In function ‘____bpf_cubic_cong_control’,
inlined from ‘bpf_cubic_cong_control’ at progs/bpf_cc_cubic.c:117:6:
progs/bpf_cc_cubic.c:130:53: error: could not inline call to
‘__builtin_memcpy’: too many bytes, use ‘-minline-memops-threshold’
130 | inet_csk(sk)->icsk_ca_state ==
TCP_CA_CWR)
```
Reduced test: -O2 -gbtf -fms-extensions #ms-extensions is essential
```
enum { TCP_CA_Recovery } typedef atomic_t;
struct in6_addr {
char u6_addr8[16];
};
struct hlist_node {
struct hlist_node *next;
struct hlist_node *pprev;
};
struct timer_list {
struct hlist_node flags_r_c[14];
};
struct sock_common {
volatile int in6_addr;
};
struct sock {
struct sock_common;
void *sk_policy2;
void *sk_backlog_rcv;
void *sk_rcuxarray;
};
struct fastopen_queue {
char nhc_flags;
int *nhc_lwtstate;
struct in6_addr;
atomic_t nhc_upper_bound;
int *__attribute__nhc_pcpu_rth_output;
int __attribute__nhc_rth_input;
int *nhc_exceptions;
};
struct flowi_tunnel {
long tun_id;
};
struct flowi_common {
int flowic_oif;
int flowic_iif;
int flowic_l3mdev;
struct flowi_tunnel;
};
struct flowi_uli {
char type;
};
struct flowi6 {
struct flowi_common;
struct in6_addr;
struct in6_addr saddr;
int flowlabel;
struct flowi_uli;
int mp_hash;
};
struct flowi {
struct flowi6;
int : 1;
};
struct inet_cork {
int addr;
int *opt;
int length;
int *dst;
int priority;
short gso_size;
int ts_opt_id;
long transmit_time;
int mark;
};
struct inet_cork_full {
struct inet_cork;
struct flowi;
};
struct inet_sock {
struct sock;
int pinet6;
int *ipv6_fl_list;
long inet_flags;
short inet_sport;
int *inet_opt;
atomic_t inet_id;
char min_ttl;
char mc_ttl;
char pmtudisc;
char rcv_tos;
char convert_csum;
int uc_index;
int mc_index;
int mc_addr;
int local_port_range;
int *mc_list;
struct inet_cork_full;
};
struct request_sock_queue {
char synflood_warned;
atomic_t qlen;
atomic_t young;
int *rskq_accept_head;
int rskq_accept_tail;
struct fastopen_queue;
};
typedef struct {
struct inet_sock icsk_inet;
struct request_sock_queue;
int icsk_bind_hash;
int *icsk_bind2_hash;
struct timer_list icsk_delack_timer;
struct timer_list;
int icsk_rto;
int icsk_rto_min;
int icsk_rto_max;
int icsk_delack_max;
int icsk_pmtu_cookie;
int *icsk_ca_ops;
int icsk_af_ops;
int *icsk_ulp_ops;
void *icsk_ulp_data;
int *icsk_sync_mss;
char icsk_ca_state: 5;
int lrcvtime;
short rcv_mss;
int : 20;
int retry;
int search_high;
int search_low;
int : 1;
int probe_timestamp;
int icsk_probes_tstamp;
int icsk_user_timeout;
long icsk_ca_priv[13];
} __attribute__((preserve_access_index)) my2_t;
char foo(my2_t *s)
{
if (s->icsk_ca_state)
return 5;
return 6;
}
```
gimple seems ok
char foo (struct my2_t * s)
{
char D.2061;
_1 = BIT_FIELD_REF <*s, 8, 7040>;
_2 = _1 & 31;
if (_2 != 0) goto <D.2059>; else goto <D.2060>;
<D.2059>:
D.2061 = 5;
// predicted unlikely by early return (on trees) predictor.
return D.2061;
<D.2060>:
D.2061 = 6;
return D.2061;
}
But Pass bpf_core_lower is generating a struct copy which leads to hitting
inlining limits
char foo (struct my2_t * s)
{
char D.2061;
D.2062 = *s; <-----
_1 = BIT_FIELD_REF <D.2062, 8, 7040>;
_2 = _1 & 31;
if (_2 != 0) goto <D.2059>; else goto <D.2060>;
<D.2059>:
D.2061 = 5;
// predicted unlikely by early return (on trees) predictor.
return D.2061;
<D.2060>:
D.2061 = 6;
return D.2061;
}