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;
}

Reply via email to