https://gcc.gnu.org/g:fb7bfbaa9192a8055683447810f08b9fa352e402
commit r16-7698-gfb7bfbaa9192a8055683447810f08b9fa352e402 Author: Cupertino Miranda <[email protected]> Date: Tue Oct 21 13:33:58 2025 +0100 bpf: Split expressions for proper CO-RE code generation This patch corrects CO-RE generation for the cases where an expression starts with a non-CO-RE access, but in the middle it requires to generate CO-RE to correctly compute the access location. It fixes it by splitting the expression into their CO-RE and non-CO-RE counterparts. It performs this by walking gimple expressions, and for each field access to which its type is a struct or union, it verifies if both the types for the base and field are attributed similarly. Otherwise, it splits the expression at this location by creating a temporary variable and performing any required pointer conversions. This smaller expressions are converted to CO-RE in the subsequent gimple walker. There is no way in GCC to distinguish nested struct/union definitions from non-nested ones. This patch simplifies code and enforces that all preserve_access_index structs/unions would be attributed explicitly. Previous approach was error prone as it would extend CO-RE accesses to structures which would not be attributed. All GCC BPF dejagnu passes tests: # of expected passes 553 # of expected failures 6 kernel-next bpf selftests: before: Summary: 543/4888 PASSED, 113 SKIPPED, 136 FAILED after: Summary: 545/4893 PASSED, 113 SKIPPED, 134 FAILED gcc/ChangeLog: PR target/120241 * config/bpf/core-builtins.cc (is_attr_preserve_access): Correct for pointer types. (maybe_get_base_for_field_expr, core_access_index_map, core_access_clean, core_is_access_index, core_mark_as_access_index): Remove. (make_gimple_core_safe_access_index): Remove function. (struct walker_data): New struct to pass data to tree walker. (callback_should_do_core_access, should_do_core_access): Add function to identify expressions that should not be converted to CO-RE. (core_make_builtins): Add callback tree walker function to convert expressions to CO-RE. (callback_find_next_split_location, core_should_split_expr, find_next_split_location, gimple_core_early_split_expr): Add function to split expressions in CO-RE and non-CO-RE expressions. (execute_lower_bpf_core): Adapt to new code. * config/bpf/bpf.opt: Add option Wco-re. * doc/invoke.texi: Add documentation for Wco-re. gcc/testsuite/ChangeLog: PR target/120241 * gcc.target/bpf/core-attr-3.c: Add attribute. * gcc.target/bpf/core-attr-4.c: Add attribute. * gcc.target/bpf/core-attr-5.c: Add attribute. * gcc.target/bpf/core-attr-6.c: Add attribute. * gcc.target/bpf/core-attr-7.c: New test. * gcc.target/bpf/core-attr-calls.c: Adapt. Diff: --- gcc/config/bpf/bpf.opt | 4 + gcc/config/bpf/core-builtins.cc | 306 +++++++++++++++++-------- gcc/doc/invoke.texi | 8 +- gcc/testsuite/gcc.target/bpf/core-attr-3.c | 4 +- gcc/testsuite/gcc.target/bpf/core-attr-4.c | 4 +- gcc/testsuite/gcc.target/bpf/core-attr-5.c | 2 +- gcc/testsuite/gcc.target/bpf/core-attr-6.c | 4 +- gcc/testsuite/gcc.target/bpf/core-attr-7.c | 150 ++++++++++++ gcc/testsuite/gcc.target/bpf/core-attr-calls.c | 4 +- 9 files changed, 378 insertions(+), 108 deletions(-) diff --git a/gcc/config/bpf/bpf.opt b/gcc/config/bpf/bpf.opt index 2803fea4970c..7d948119586f 100644 --- a/gcc/config/bpf/bpf.opt +++ b/gcc/config/bpf/bpf.opt @@ -112,3 +112,7 @@ Enum(asm_dialect) String(pseudoc) Value(ASM_PSEUDOC) minline-memops-threshold= Target RejectNegative Joined UInteger Var(bpf_inline_memops_threshold) Init(1024) -minline-memops-threshold=<number> Maximum size of memset/memmove/memcpy to inline, larger sizes will use a library call. + +Wbpf-core +Target Warning +Warn when CO-RE support is not guaranteed. diff --git a/gcc/config/bpf/core-builtins.cc b/gcc/config/bpf/core-builtins.cc index d366b7c06a4f..d0c6cfdaf1c0 100644 --- a/gcc/config/bpf/core-builtins.cc +++ b/gcc/config/bpf/core-builtins.cc @@ -324,8 +324,13 @@ is_attr_preserve_access (tree t) TYPE_ATTRIBUTES (TREE_TYPE (base))); if (TREE_CODE (base) == MEM_REF) - return lookup_attribute ("preserve_access_index", - TYPE_ATTRIBUTES (TREE_TYPE (base))); + { + tree type = TREE_TYPE (base); + if (POINTER_TYPE_P (type)) + type = TREE_TYPE (type); + return lookup_attribute ("preserve_access_index", + TYPE_ATTRIBUTES (type)); + } if (TREE_CODE (t) == COMPONENT_REF) { @@ -1710,137 +1715,241 @@ bpf_output_core_reloc (rtx *operands, int nr_ops) } } +/* This function verifies if the passed tree node t is a struct field + expression and if at this location is is necessary to break the expression + in order to split CO-RE and non CO-RE required field/union accesses. */ + +static bool +core_should_split_expr (tree t) +{ + tree type = TREE_TYPE (t); + if (TREE_CODE (type) != RECORD_TYPE + && TREE_CODE (type) != UNION_TYPE) + return false; + + if (TREE_CODE (t) == COMPONENT_REF) + { + tree base = TREE_OPERAND (t, 0); + + bool base_is_attr = lookup_attribute ("preserve_access_index", + TYPE_ATTRIBUTES (TREE_TYPE (base))) != NULL_TREE; + bool cur_is_attr = lookup_attribute ("preserve_access_index", + TYPE_ATTRIBUTES (TREE_TYPE (t))) != NULL_TREE; + + if (base_is_attr != cur_is_attr) + return true; + } + return false; +} + +struct walker_data { + bool is_root; + tree *core_base_pointer; +}; + static tree -maybe_get_base_for_field_expr (tree expr) +callback_find_next_split_location (tree *tp, + int *walk_subtrees ATTRIBUTE_UNUSED, + void *data) { - poly_int64 bitsize, bitpos; - tree var_off; - machine_mode mode; - int sign, reverse, vol; + struct walker_data *d = (struct walker_data *) data; - if (expr == NULL_TREE) + if (d->is_root == true && TREE_CODE (*tp) == ADDR_EXPR) return NULL_TREE; - return get_inner_reference (expr, &bitsize, &bitpos, &var_off, &mode, - &sign, &reverse, &vol); + if (d->is_root == false && core_should_split_expr (*tp)) + { + d->core_base_pointer = tp; + return *tp; + } + else + { + /* Keep walking the expression. */ + d->is_root = false; + return NULL_TREE; + } } -/* Access functions to mark sub expressions as attributed with - __preserve_access_index. - This is required since in gimple format, in order to convert an expression as - CO-RE safe, we must create multiple gimple statements. - Also, only the type of the base of the expression might be attributed with - __preserve_access_index. Nevertheless all the consecutive accesses to this - attributed node should also be converted to CO-RE safe. - Any LHS assigned values with CO-RE converted expressions are marked and - any uses of these values are later checked for further convertion. - The core_access_index_map functions allow to mark this nodes for later - convertion to CO-RE. - This mechanism are used by make_gimple_core_safe_access_index. */ - -static GTY(()) hash_map<tree, tree> *core_access_index_map = NULL; +/* Walk an expression and return the node at any location in the expression + where we should break the expression in its CO-RE and non CO-RE parts. */ -static void -core_access_clean (void) +static tree * +find_next_split_location (tree *tp, bool is_first) { - if (core_access_index_map == NULL) - core_access_index_map = hash_map<tree, tree>::create_ggc (10); - core_access_index_map->empty (); + struct walker_data data = { is_first, NULL }; + walk_tree (tp, callback_find_next_split_location, &data, NULL); + return data.core_base_pointer; } -static bool -core_is_access_index (tree expr) + +static tree +callback_should_do_core_access (tree *tp, + int *walk_subtrees ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) { - if (TREE_CODE (expr) == MEM_REF - || TREE_CODE (expr) == INDIRECT_REF) - expr = TREE_OPERAND (expr, 0); +/* TODO NOTE: This might have to be removed later as it is an exception + to mimic clang behavior. We need to confirm if the attribute "packed" + should disable any CO-RE access in any of its children fields. */ + if (lookup_attribute ("packed", TYPE_ATTRIBUTES (TREE_TYPE (*tp)))) + { + warning_at (EXPR_LOC_OR_LOC (*tp, UNKNOWN_LOCATION), OPT_Wbpf_core, + "Access through packed struct may not be possible to patch for CO-RE"); + return *tp; + } + return NULL_TREE; +} - tree *def = core_access_index_map->get (expr); - if (def) - return true; - return false; + +static bool +should_do_core_access (tree *tp) +{ + tree tfail = walk_tree (tp, callback_should_do_core_access, NULL, NULL); + return tfail == NULL_TREE; } -static void -core_mark_as_access_index (tree expr) +/* This is the main callback function to the gimple traversal that will split + any field/union accesses in their CO-RE and non CO-RE parts. + An early version of this callback would allow also allow its walker function + to traverse the parent tree expression on any initial expression (children + tree node), by not setting walk_subtrees to false. In current version only + the main tree node of an expression is reached by the traversal function + that uses this callback. The sub traversal of the main tree nodes is done in + find_next_split_location call. The function iterates on the parent + expressions within the loop that call find_next_split_location function. */ + +static tree +gimple_core_early_split_expr (tree *tp, + int *walk_subtrees, + void *data) { - if (TREE_CODE (expr) == MEM_REF - || TREE_CODE (expr) == INDIRECT_REF) - expr = TREE_OPERAND (expr, 0); + struct walk_stmt_info *wi = (struct walk_stmt_info *) data; + tree *split_loc = tp; - if (core_access_index_map->get (expr) == NULL) - core_access_index_map->put (expr, NULL_TREE); -} + if (!should_do_core_access (tp)) + { + *walk_subtrees = false; + return NULL_TREE; + } + + /* Find the next split location within expression tree. */ + tree *expr = NULL; + bool is_first = true; + while ((expr = find_next_split_location (split_loc, is_first)) != NULL) + { + gimple_seq before = NULL; + + if (*expr == *split_loc && is_first == true) + break; + is_first = false; -/* This function is an adaptation of make_core_safe_access_index but to be used - in gimple format trees. It is used by execute_lower_bpf_core, when - traversing the gimple tree looking for nodes that would have its type - attributed with __preserve_access_index. In this particular cases any of - the expressions using such attributed types must be made CO-RE safe. */ + push_gimplify_context (); + split_loc = &TREE_OPERAND (*expr, 0); + + tree rhs = *expr; + bool pointer_base = false; + if (!POINTER_TYPE_P (TREE_TYPE (rhs))) + { + rhs = fold_build1 (ADDR_EXPR, + build_pointer_type (TREE_TYPE (*expr)), + *expr); + pointer_base = true; + } + tree lhs = create_tmp_var_raw (TREE_TYPE (rhs), "core_split"); + gimple_add_tmp_var (lhs); + gimplify_assign (lhs, rhs, &before); + + if (pointer_base == true) + lhs = fold_build2 (MEM_REF, TREE_TYPE (lhs), lhs, + build_int_cst (ptr_type_node, 0)); + *expr = lhs; + + gsi_insert_seq_before (&(wi->gsi), before, GSI_NEW_STMT); + pop_gimplify_context (NULL); + } + + /* Never traverse subtrees, as find_next_split_location already does it. */ + *walk_subtrees = false; + + /* Keep traverse all the other tree expressions in gimple. */ + return NULL_TREE; +} static tree -make_gimple_core_safe_access_index (tree *tp, - int *walk_subtrees ATTRIBUTE_UNUSED, - void *data) +core_make_builtins (tree *tp, int *walk_subtrees, void *data) { struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - bool valid = true; int n = 0; + bool valid = true; + tree expr = *tp; + bool is_addr_expr = false; - tree *patch = tp; - if (TREE_CODE (*patch) == ADDR_EXPR) - patch = &(TREE_OPERAND (*tp, 0)); - tree orig_type = TREE_TYPE (*patch); + if (!should_do_core_access (tp)) + { + *walk_subtrees = false; + return NULL_TREE; + } - if ((is_attr_preserve_access (*patch) - || core_is_access_index (maybe_get_base_for_field_expr (*patch))) - && (n = compute_field_expr (*patch, NULL, &valid, NULL)) > 0 + /* Skip ADDR_EXPR node since we will convert to pointer anyway. */ + if (TREE_CODE (*tp) == ADDR_EXPR) + { + is_addr_expr = true; + expr = TREE_OPERAND (*tp, 0); + } + + if (is_attr_preserve_access (expr) + && (n = compute_field_expr (expr, NULL, &valid, NULL)) > 0 && valid == true) { - bool changed = false; - tree expr_test = make_core_safe_access_index (*patch, &changed); + poly_int64 bitsize, bitpos; + tree var_off; + machine_mode mode; + int sign, reverse, vol; + tree base = get_inner_reference (expr, &bitsize, &bitpos, &var_off, &mode, + &sign, &reverse, &vol); - gimple_seq before = NULL; - push_gimplify_context (); - gimplify_expr (&expr_test, &before, NULL, is_gimple_val, fb_rvalue); + tree new_expr = core_expr_with_field_expr_plus_base (base, expr, true); - /* In case the ADDR_EXPR bypassed above is no longer needed. */ - if (patch != tp && TREE_TYPE (expr_test) == TREE_TYPE (*tp)) - *tp = expr_test; - /* For non pointer value accesses. */ - else if (TREE_TYPE (expr_test) == build_pointer_type (orig_type)) - *patch = fold_build2 (MEM_REF, TREE_TYPE (*patch), - expr_test, build_int_cst (ptr_type_node, 0)); - else - *patch = expr_test; + /* Abort convertion if it is just a pointer or a reference to an + attributed type. */ + if (new_expr != expr) + { - *tp = fold (*tp); + gimple_seq before = NULL; + push_gimplify_context (); - gsi_insert_seq_before (&(wi->gsi), before, GSI_LAST_NEW_STMT); - pop_gimplify_context (NULL); + gimplify_expr (&new_expr, &before, NULL, is_gimple_val, fb_rvalue); - wi->changed = true; - *walk_subtrees = false; + tree new_expr_type = TREE_TYPE (new_expr); + + /* Replace original expression by new_expr. If the type is the same + tree node, good! If it is a pointer type, we need to dereference + the type within the pointer to guarantee it is the same. */ + if (TREE_TYPE (new_expr) == TREE_TYPE (*tp) + || (is_addr_expr + && TREE_TYPE (new_expr_type) == TREE_TYPE (expr))) + *tp = fold (new_expr); + else if (TREE_TYPE (new_expr) == build_pointer_type (TREE_TYPE (*tp))) + *tp = fold_build2 (MEM_REF, TREE_TYPE (*tp), + new_expr, build_int_cst (ptr_type_node, 0)); + else + gcc_assert (0); - tree lhs; - if (!wi->is_lhs - && gimple_code (wi->stmt) != GIMPLE_CALL - && (lhs = gimple_get_lhs (wi->stmt)) != NULL_TREE) - core_mark_as_access_index (lhs); + gsi_insert_seq_before (&(wi->gsi), before, GSI_SAME_STMT); + pop_gimplify_context (NULL); + + *walk_subtrees = false; + } } return NULL_TREE; } /* This is the entry point for the pass_data_lower_bpg_core. It walks all the statements in gimple, looking for expressions that are suppose to be CO-RE - preserve_access_index attributed. - Those expressions are processed and split by - make_gimple_core_safe_access_index function, which will both create the - calls to __build_core_reloc and split the expression in smaller parts in - case it cannot be represented CO-RE safeguarded by a single CO-RE - relocation. */ - + preserve_access_index attributed, and should not. + It first splits CO-RE expressions from non CO-RE ones. + Then the CO-RE expressions are processed by core_make_builtins which will + create the required builtins that will result in the CO-RE relocations. */ static unsigned int execute_lower_bpf_core (void) { @@ -1851,13 +1960,14 @@ execute_lower_bpf_core (void) gimple_seq body = gimple_body (current_function_decl); struct walk_stmt_info wi; - core_access_clean (); - memset (&wi, 0, sizeof (wi)); - wi.info = NULL; - /* Split preserve_access_index expressions when needed. */ - walk_gimple_seq_mod (&body, NULL, make_gimple_core_safe_access_index, &wi); + /* Early split to guarantee base of expression is a preserve_access_index + structure. */ + walk_gimple_seq_mod (&body, NULL, gimple_core_early_split_expr, &wi); + + /* Add CO-RE builtins for all expressions that need them. */ + walk_gimple_seq_mod (&body, NULL, core_make_builtins, &wi); return 0; } diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index ad4d2e645d1e..6440e7cd3696 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1087,7 +1087,8 @@ Objective-C and Objective-C++ Dialects}. @gccoptlist{-mbig-endian -mlittle-endian -mframe-limit=@var{bytes} -mxbpf -mco-re -mjmpext -mjmp32 -malu32 -mv3-atomics -mbswap -msdiv -msmov -mcpu=@var{version} --masm=@var{dialect} -minline-memops-threshold=@var{bytes}} +-masm=@var{dialect} -minline-memops-threshold=@var{bytes} +-Wco-re} @emph{FR30 Options} (@ref{FR30 Options}) @gccoptlist{-msmall-model -mno-lsim} @@ -26441,6 +26442,11 @@ a library call instead of being expanded inline, but since BPF doesn't allow libcalls, exceeding this threshold results in a compile-time error. The default is @samp{1024} bytes. +@opindex Wco-re +@item -Wco-re +Enable warnings for scenarios where -mco-re is enabled, but it may not be +possible to generate CO-RE compatible code. + @end table @node FR30 Options diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-3.c b/gcc/testsuite/gcc.target/bpf/core-attr-3.c index 12354fc6f86d..58c27fd43bb4 100644 --- a/gcc/testsuite/gcc.target/bpf/core-attr-3.c +++ b/gcc/testsuite/gcc.target/bpf/core-attr-3.c @@ -11,14 +11,14 @@ struct O { int e; int f; -}; +} __attribute__((preserve_access_index)); struct S { int a; struct { int b; int c; - } inner; + } __attribute__((preserve_access_index)) inner; struct O other; } __attribute__((preserve_access_index)); diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-4.c b/gcc/testsuite/gcc.target/bpf/core-attr-4.c index 6f025f42f3ee..c001b5b76ef9 100644 --- a/gcc/testsuite/gcc.target/bpf/core-attr-4.c +++ b/gcc/testsuite/gcc.target/bpf/core-attr-4.c @@ -13,8 +13,8 @@ struct T { int d; int e[4]; int f; - } v; - } u; + } __attribute__((preserve_access_index)) v; + } __attribute__((preserve_access_index)) u; } __attribute__((preserve_access_index)); diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-5.c b/gcc/testsuite/gcc.target/bpf/core-attr-5.c index 81e25fa85de7..4d443d88b0ae 100644 --- a/gcc/testsuite/gcc.target/bpf/core-attr-5.c +++ b/gcc/testsuite/gcc.target/bpf/core-attr-5.c @@ -11,7 +11,7 @@ struct U { int e[4]; int f; int *g; - } v; + } __attribute__((preserve_access_index)) v; } __attribute__((preserve_access_index)); struct T { diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-6.c b/gcc/testsuite/gcc.target/bpf/core-attr-6.c index 25215b5ae376..d43825ea97c3 100644 --- a/gcc/testsuite/gcc.target/bpf/core-attr-6.c +++ b/gcc/testsuite/gcc.target/bpf/core-attr-6.c @@ -11,8 +11,8 @@ struct U { int e[4]; int f; int *g; - } v; -} u; + } __attribute__((preserve_access_index)) v; +} __attribute__((preserve_access_index)) u; struct T { int a; diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-7.c b/gcc/testsuite/gcc.target/bpf/core-attr-7.c new file mode 100644 index 000000000000..342f69e379ba --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-attr-7.c @@ -0,0 +1,150 @@ +/* Test for BPF CO-RE __attribute__((preserve_access_index)) with accesses on + LHS and both LHS and RHS of assignment. */ + +/* { dg-do compile } */ +/* { dg-options "-O2 -dA -gbtf -mco-re -masm=normal" } */ + +struct other +{ + char c; + int i; +}; + +struct inner_attr1 +{ + int i1; + int i2; +} __attribute__((preserve_access_index)); + +struct inner_noattr +{ + int i1; + int i2; +}; + +union A_noattr +{ + struct inner_attr1 inner_attr; + struct inner_noattr inner_no_attr; + struct inner_noattr *inner_p; +}; +union A_attr +{ + struct inner_attr1 inner_attr; + struct inner_noattr inner_no_attr; + struct inner_noattr *inner_p; +} __attribute__((preserve_access_index)); + + +struct outer_noattr +{ + struct other *other; + struct inner_attr + { + int i1; + int i2; + } __attribute__((preserve_access_index)) inner; + struct inner_noattr inner_no_attr; + struct inner_attr1 *inner_p; + union A_attr a_attr; + union A_noattr a_noattr; +}; + +struct outer_attr +{ + struct other *other; + struct inner_attr + { + int i1; + int i2; + } __attribute__((preserve_access_index)) inner; + + struct inner_noattr inner_no_attr; + struct inner_attr1 *inner_p; + union A_attr a_attr; + union A_noattr a_noattr; +} __attribute__((preserve_access_index)); + +extern void use_value(int); + +void +func (struct outer_noattr *o, struct outer_attr *o_attr) +{ + /* 0:1 */ + o->inner.i2 = 7; + /* 0:1 */ + o->inner_p->i2 = 8; + /* nothing */ + o->inner_no_attr.i2 = 9; + + /* 0:2 */ + o_attr->inner_no_attr.i2 = 10; + + /* nothing */ + o->a_noattr.inner_no_attr.i1 = 1; + /* 0:1 */ + o->a_attr.inner_no_attr.i1 = 2; + /* 0:0 */ + o->a_noattr.inner_attr.i1 = 3; + /* 0:4:0:0 */ + o_attr->a_attr.inner_attr.i1 = 4; + /* 0:5 0:0 */ + o_attr->a_noattr.inner_attr.i1 = 5; + + /* This would still force everything as being attributed, although none of + the structs has the attribute. */ + /* 0:5:2 0:0 */ + __builtin_preserve_access_index (({ o->a_noattr.inner_p->i1 = 20; })); + + /* 0:2 */ + struct inner_noattr d = o_attr->inner_no_attr; + use_value(d.i2); +} + + +extern void use(void *); + +struct udphdr { + int source; + int dest; + int len; + int check; +} __attribute__((preserve_access_index)); + +union l4hdr { + struct udphdr udp; + int c; +}; + +struct v4hdr { + int a; + union l4hdr l4hdr; + int b; +}; + +void gimple_loop_error(void) +{ + struct v4hdr h_outer; + h_outer.l4hdr.udp.source = 1024; + use(&h_outer.l4hdr.udp.source); +} + +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:5.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:4:0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:5:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:0\"\\)" 4 } } */ +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1\"\\)" 3 } } */ +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:2\"\\)" 2 } } */ +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:5\"\\)" 1 } } */ +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:4:0:0\"\\)" 1 } } */ +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:5:2\"\\)" 1 } } */ +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct inner_attr\\)" 1 } } */ +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct inner_attr1\\)" 3 } } */ +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct outer_attr\\)" 4 } } */ +/* { dg-final { scan-assembler-times "bpfcr_type \\(union A_attr\\)" 1 } } */ + + diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-calls.c b/gcc/testsuite/gcc.target/bpf/core-attr-calls.c index 87290c5c2116..27b08af1bb79 100644 --- a/gcc/testsuite/gcc.target/bpf/core-attr-calls.c +++ b/gcc/testsuite/gcc.target/bpf/core-attr-calls.c @@ -37,13 +37,13 @@ func (struct T *t, int i) /* 0:3 */ get_other_u(t->ptr_u)->c = 43; - /* 0:2:1 */ + /* 0:2 */ get_other_v(&t->u.v)->d = 44; } /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:3\"\\)" 2 } } */ /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:0\"\\)" 1 } } */ -/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:2:1\"\\)" 1 } } */ +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:2\"\\)" 1 } } */ /* { dg-final { scan-assembler-times "bpfcr_type \\(struct T\\)" 3 } } */ /* { dg-final { scan-assembler-times "bpfcr_type \\(struct U\\)" 1 } } */
