From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2049) id 047673856262; Thu, 5 May 2022 12:09:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 047673856262 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Matthew Malcomson To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/vendors/ARM/heads/morello)] c: Propagate capability-ness through &addr->foo etc. X-Act-Checkin: gcc X-Git-Author: Richard Sandiford X-Git-Refname: refs/vendors/ARM/heads/morello X-Git-Oldrev: 69d1babe4658e807e9bb9fbafb912af9d306a642 X-Git-Newrev: 3c8cbe08bea173f7878b2313c353d7bdcea920e5 Message-Id: <20220505120939.047673856262@sourceware.org> Date: Thu, 5 May 2022 12:09:39 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 05 May 2022 12:09:39 -0000 https://gcc.gnu.org/g:3c8cbe08bea173f7878b2313c353d7bdcea920e5 commit 3c8cbe08bea173f7878b2313c353d7bdcea920e5 Author: Richard Sandiford Date: Wed Apr 20 19:16:17 2022 +0100 c: Propagate capability-ness through &addr->foo etc. This patch makes expressions like: &addr->foo &addr[i] &*addr etc. have capability type whenever addr has capability type. It also makes array-to-pointer conversion return a capability type whenever the base address of the array is a capability, such as in: cap->array + 0 The patch adds a c_build_addr_expr function that enforces these rules and (defensively) uses the function for all instances of: build_unary_op (..., unqualified_addr_expr (), ...) even those (like omp) that we're not in a position to test properly. I wondered about putting some of this in c-family, but I think the C++ version is likely to look significantly different. The code is also quite tightly tied to the C-specific lvalue_p function. Clang agrees on the assertions in the testcase, except for the CAP ones for __real and __imag lvalues. I think that's a bug in clang though. Diff: --- gcc/c/c-decl.c | 3 +- gcc/c/c-parser.c | 16 +- gcc/c/c-tree.h | 2 + gcc/c/c-typeck.c | 80 +++++++-- .../aarch64/morello/hybrid-addr-expr-10.c | 200 +++++++++++++++++++++ 5 files changed, 279 insertions(+), 22 deletions(-) diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 8392076ec88..86805630ea2 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -5548,8 +5548,7 @@ finish_decl (tree decl, location_t init_loc, tree init, vec *v; /* Build "cleanup(&decl)" for the destructor. */ - cleanup = build_unary_op (input_location, unqualified_addr_expr (), - decl, false); + cleanup = c_build_addr_expr (input_location, decl, false); vec_alloc (v, 1); v->quick_push (cleanup); cleanup = c_build_function_call_vec (DECL_SOURCE_LOCATION (decl), diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index afb99f03f3f..dc8893d3f5c 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -8237,10 +8237,13 @@ c_parser_unary_expression (c_parser *parser) op = default_function_array_read_conversion (exp_loc, op); return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op); case CPP_AND: - c_parser_consume_token (parser); - op = c_parser_cast_expression (parser, NULL); - mark_exp_read (op.value); - return parser_build_unary_op (op_loc, unqualified_addr_expr (), op); + { + c_parser_consume_token (parser); + op = c_parser_cast_expression (parser, NULL); + mark_exp_read (op.value); + tree_code code = c_addr_expr_code_for_arg (op.value); + return parser_build_unary_op (op_loc, code, op); + } case CPP_MULT: { c_parser_consume_token (parser); @@ -17874,9 +17877,8 @@ c_parser_omp_depobj (c_parser *parser) } else { - tree addr = build_unary_op (EXPR_LOC_OR_LOC (depobj, loc), - unqualified_addr_expr (), - depobj, false); + tree addr = c_build_addr_expr (EXPR_LOC_OR_LOC (depobj, loc), + depobj, false); if (addr == error_mark_node) depobj = error_mark_node; else diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index cf428ba0be0..423b82e3381 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -687,6 +687,7 @@ extern tree build_component_ref (location_t, tree, tree, location_t); extern tree build_array_ref (location_t, tree, tree); extern tree build_external_ref (location_t, tree, bool, tree *); extern void pop_maybe_used (bool); +extern tree_code c_addr_expr_code_for_arg (tree); extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr); extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *); extern struct c_expr parser_build_unary_op (location_t, enum tree_code, @@ -694,6 +695,7 @@ extern struct c_expr parser_build_unary_op (location_t, enum tree_code, extern struct c_expr parser_build_binary_op (location_t, enum tree_code, struct c_expr, struct c_expr); +extern tree c_build_addr_expr (location_t, tree, bool); extern tree build_conditional_expr (location_t, tree, bool, tree, tree, location_t, tree, tree, location_t); extern tree build_compound_expr (location_t, tree, tree); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 8bd7e286e93..a40d5eb21c4 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -1925,7 +1925,7 @@ array_to_pointer_conversion (location_t loc, tree exp) if (TREE_NO_WARNING (orig_exp)) TREE_NO_WARNING (exp) = 1; - ptrtype = build_pointer_type (restype); + ptrtype = addr_expr_type (c_addr_expr_code_for_arg (exp), restype); if (INDIRECT_REF_P (exp)) return convert (ptrtype, TREE_OPERAND (exp, 0)); @@ -1942,7 +1942,7 @@ array_to_pointer_conversion (location_t loc, tree exp) "is ill-formed in C++"); } - adr = build_unary_op (loc, unqualified_addr_expr (), exp, true); + adr = c_build_addr_expr (loc, exp, true); return convert (ptrtype, adr); } @@ -1959,7 +1959,7 @@ function_to_pointer_conversion (location_t loc, tree exp) if (TREE_NO_WARNING (orig_exp)) TREE_NO_WARNING (exp) = 1; - return build_unary_op (loc, unqualified_addr_expr (), exp, false); + return c_build_addr_expr (loc, exp, false); } /* Mark EXP as read, not just set, for set but not used -Wunused @@ -2106,8 +2106,7 @@ convert_lvalue_to_rvalue (location_t loc, struct c_expr exp, vec *params; tree nonatomic_type, tmp, tmp_addr, fndecl, func_call; tree expr_type = TREE_TYPE (exp.value); - tree expr_addr = build_unary_op (loc, unqualified_addr_expr (), - exp.value, false); + tree expr_addr = c_build_addr_expr (loc, exp.value, false); tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST); gcc_assert (TYPE_ATOMIC (expr_type)); @@ -2120,7 +2119,7 @@ convert_lvalue_to_rvalue (location_t loc, struct c_expr exp, create the VAL temp variable to hold the RHS. */ nonatomic_type = build_qualified_type (expr_type, TYPE_UNQUALIFIED); tmp = create_tmp_var_raw (nonatomic_type); - tmp_addr = build_unary_op (loc, unqualified_addr_expr (), tmp, false); + tmp_addr = c_build_addr_expr (loc, tmp, false); TREE_ADDRESSABLE (tmp) = 1; TREE_NO_WARNING (tmp) = 1; @@ -4090,7 +4089,7 @@ build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode, tree loop_label, loop_decl, done_label, done_decl; tree lhs_type = TREE_TYPE (lhs); - tree lhs_addr = build_unary_op (loc, unqualified_addr_expr (), lhs, false); + tree lhs_addr = c_build_addr_expr (loc, lhs, false); tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST); tree rhs_semantic_type = TREE_TYPE (rhs); tree nonatomic_rhs_semantic_type; @@ -4140,7 +4139,7 @@ build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode, if (modifycode == NOP_EXPR) { /* Build __atomic_store (&lhs, &val, SEQ_CST) */ - rhs = build_unary_op (loc, unqualified_addr_expr (), val, false); + rhs = c_build_addr_expr (loc, val, false); fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_STORE); params->quick_push (lhs_addr); params->quick_push (rhs); @@ -4245,12 +4244,12 @@ build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode, cas_loop: /* Create the variables and labels required for the op= form. */ old = create_tmp_var_raw (nonatomic_lhs_type); - old_addr = build_unary_op (loc, unqualified_addr_expr (), old, false); + old_addr = c_build_addr_expr (loc, old, false); TREE_ADDRESSABLE (old) = 1; TREE_NO_WARNING (old) = 1; newval = create_tmp_var_raw (nonatomic_lhs_type); - newval_addr = build_unary_op (loc, unqualified_addr_expr (), newval, false); + newval_addr = c_build_addr_expr (loc, newval, false); TREE_ADDRESSABLE (newval) = 1; TREE_NO_WARNING (newval) = 1; @@ -4961,6 +4960,8 @@ lvalue_p (const_tree ref) { const enum tree_code code = TREE_CODE (ref); + /* Changes to this switch statement should also be reflected in + c_addr_expr_code_for_arg. */ switch (code) { case REALPART_EXPR: @@ -4994,6 +4995,60 @@ lvalue_p (const_tree ref) return false; } } + +/* If ARG is an lvalue, return the address-of operator for &ARG, + otherwise return the default address-of operator. */ + +tree_code +c_addr_expr_code_for_arg (tree arg) +{ + /* This switch statement is based on the structure of the one in lvalue_p. + The idea is to peel off component references in an lvalue until we + find the first pointer-derived access. The operator should then be + CAP_ADDR_EXPR if that pointer is a capability and NONCAP_ADDR_EXPR + otherwise. + + If there are no pointer accesses (e.g. because the base of the access + is a constant or decl) then we should instead use the operator for + general pointers, given by unqualified_addr_expr. */ + switch (TREE_CODE (arg)) + { + case REALPART_EXPR: + case IMAGPART_EXPR: + case COMPONENT_REF: + return c_addr_expr_code_for_arg (TREE_OPERAND (arg, 0)); + + case C_MAYBE_CONST_EXPR: + return c_addr_expr_code_for_arg (TREE_OPERAND (arg, 1)); + + case INDIRECT_REF: + /* Base the choice of operator on whether the pointer is a + capability. */ + return addr_expr_code (TREE_TYPE (TREE_OPERAND (arg, 0))); + + case ARRAY_REF: + /* As for INDIRECT_REF if the index is applied to a pointer base. + Recurse if the index is instead applied to a true array. */ + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 0))) == ARRAY_TYPE) + return c_addr_expr_code_for_arg (TREE_OPERAND (arg, 0)); + return addr_expr_code (TREE_TYPE (TREE_OPERAND (arg, 0))); + + default: + /* For now, this includes gimple MEM_REFs, on the basis that + (a) gimple allows __CAP_ADDR to be specified directly and + (b) gimple isn't supposed to be user-friendly. */ + return unqualified_addr_expr (); + } +} + +/* Like build_unary_op, but specifically for the operation &ARG. */ + +tree +c_build_addr_expr (location_t location, tree arg, bool noconvert) +{ + return build_unary_op (location, c_addr_expr_code_for_arg (arg), + arg, noconvert); +} /* Give a warning for storing in something that is read-only in GCC terms but not const in ISO C terms. */ @@ -14848,9 +14903,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } if (!remove) { - tree addr = build_unary_op (OMP_CLAUSE_LOCATION (c), - unqualified_addr_expr (), - t, false); + tree addr = c_build_addr_expr (OMP_CLAUSE_LOCATION (c), + t, false); if (addr == error_mark_node) remove = true; else diff --git a/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-10.c b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-10.c new file mode 100644 index 00000000000..0fd69b8cfc4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-10.c @@ -0,0 +1,200 @@ +/* { dg-do compile } */ + +#define CAP(X) _Static_assert(sizeof(X) == sizeof(void *__capability)) +#define NONCAP(X) _Static_assert(sizeof(X) == sizeof(void *)) + +//---------------------------------------------------------- + +int *__capability int_cap; +int *int_ptr; +int int_var; +struct { int f[2]; } int_struct; + +CAP (int_cap); +NONCAP (int_ptr); + +CAP (&*int_cap); +NONCAP (&*int_ptr); +NONCAP (&int_var); +NONCAP (&int_struct.f[0]); + +//---------------------------------------------------------- + +__intcap *__capability intcap_cap; +__intcap *intcap_ptr; +__intcap intcap_var; +struct { __intcap f[2]; } intcap_struct; + +CAP (&*intcap_cap); +NONCAP (&*intcap_ptr); +NONCAP (&intcap_var); +NONCAP (&intcap_struct.f[0]); + +//---------------------------------------------------------- + +int *__capability *__capability int_cap_cap; +int **__capability int_ptr_cap; +int *__capability *int_cap_ptr; +int **int_ptr_ptr; + +CAP (&int_cap_cap[0]); +CAP (&int_ptr_cap[0]); +NONCAP (&int_cap_ptr[0]); +NONCAP (&int_ptr_ptr[0]); + +CAP (&*int_cap_cap); +CAP (&*int_ptr_cap); +NONCAP (&*int_cap_ptr); +NONCAP (&*int_ptr_ptr); + +CAP (&int_cap_cap[0][0]); +CAP (&int_cap_ptr[0][0]); +NONCAP (&int_ptr_cap[0][0]); +NONCAP (&int_ptr_ptr[0][0]); + +CAP (&**int_cap_cap); +CAP (&**int_cap_ptr); +NONCAP (&**int_ptr_cap); +NONCAP (&**int_ptr_ptr); + +//---------------------------------------------------------- + +_Complex int *__capability complex_cap; +_Complex int *complex_ptr; +_Complex int complex_var; +struct { _Complex int f[2]; } complex_struct; + +CAP (&__real complex_cap[0]); +CAP (&__imag complex_cap[0]); +NONCAP (&__real complex_ptr[0]); +NONCAP (&__imag complex_ptr[0]); + +CAP (&__real *complex_cap); +CAP (&__imag *complex_cap); +NONCAP (&__real *complex_ptr); +NONCAP (&__imag *complex_ptr); +NONCAP (&__real complex_var); +NONCAP (&__imag complex_var); +NONCAP (&__real complex_struct.f[0]); +NONCAP (&__imag complex_struct.f[1]); + +//---------------------------------------------------------- + +int (*__capability int_arr_cap_arr[100])[200]; +int (*int_arr_ptr_arr[100])[200]; +int int_arr_arr[100][200]; + +NONCAP (&int_arr_cap_arr); +NONCAP (&int_arr_ptr_arr); +NONCAP (&int_arr_arr); + +NONCAP (int_arr_cap_arr + 0); +NONCAP (int_arr_ptr_arr + 0); +NONCAP (int_arr_arr + 0); + +NONCAP (&*int_arr_cap_arr); +NONCAP (&*int_arr_ptr_arr); +NONCAP (&*int_arr_arr); + +NONCAP (&int_arr_cap_arr[0]); +NONCAP (&int_arr_ptr_arr[0]); +NONCAP (&int_arr_arr[0]); + +CAP (**int_arr_cap_arr + 0); +NONCAP (**int_arr_ptr_arr + 0); + +CAP (*int_arr_cap_arr[0] + 0); +NONCAP (*int_arr_ptr_arr[0] + 0); +NONCAP (*int_arr_arr + 0); + +CAP (int_arr_cap_arr[0][0] + 0); +NONCAP (int_arr_ptr_arr[0][0] + 0); +NONCAP (int_arr_arr[0] + 0); + +CAP (&**int_arr_cap_arr); +NONCAP (&**int_arr_ptr_arr); +NONCAP (&**int_arr_arr); + +CAP (&*int_arr_cap_arr[0]); +NONCAP (&*int_arr_ptr_arr[0]); +NONCAP (&*int_arr_arr[0]); + +CAP (&int_arr_cap_arr[0][0]); +NONCAP (&int_arr_ptr_arr[0][0]); +NONCAP (&int_arr_arr[0][0]); + +CAP (&***int_arr_cap_arr); +NONCAP (&***int_arr_ptr_arr); + +CAP (&**int_arr_cap_arr[0]); +NONCAP (&**int_arr_ptr_arr[0]); + +CAP (&*int_arr_cap_arr[0][0]); +NONCAP (&*int_arr_ptr_arr[0][0]); + +CAP (&int_arr_cap_arr[0][0][0]); +NONCAP (&int_arr_ptr_arr[0][0][0]); + +//---------------------------------------------------------- + +struct s { + struct s *__capability link_cap; + struct s *link_ptr; +}; +struct s *__capability root_cap; +struct s *root_ptr; +struct s root_var; +struct s root_arr[4]; + +NONCAP (&root_cap); +NONCAP (&root_ptr); +NONCAP (&root_var); +NONCAP (&root_arr); + +CAP (&*root_cap); +NONCAP (&*root_ptr); +NONCAP (&*root_arr); + +CAP (&root_cap->link_cap); +CAP (&root_cap->link_ptr); +NONCAP (&root_ptr->link_cap); +NONCAP (&root_ptr->link_ptr); +NONCAP (&root_var.link_cap); +NONCAP (&root_var.link_ptr); +NONCAP (&root_arr->link_cap); +NONCAP (&root_arr->link_ptr); +NONCAP (&root_arr[0].link_cap); +NONCAP (&root_arr[0].link_ptr); + +CAP (&*root_cap->link_cap); +NONCAP (&*root_cap->link_ptr); +CAP (&*root_ptr->link_cap); +NONCAP (&*root_ptr->link_ptr); +CAP (&*root_var.link_cap); +NONCAP (&*root_var.link_ptr); +CAP (&*root_arr->link_cap); +NONCAP (&*root_arr->link_ptr); +CAP (&*root_arr[0].link_cap); +NONCAP (&*root_arr[0].link_ptr); + +CAP (&root_cap->link_cap->link_cap); +NONCAP (&root_cap->link_ptr->link_cap); +CAP (&root_ptr->link_cap->link_cap); +NONCAP (&root_ptr->link_ptr->link_cap); +CAP (&root_var.link_cap->link_cap); +NONCAP (&root_var.link_ptr->link_cap); +CAP (&root_arr->link_cap->link_cap); +NONCAP (&root_arr->link_ptr->link_cap); +CAP (&root_arr[0].link_cap->link_cap); +NONCAP (&root_arr[0].link_ptr->link_cap); + +CAP (&root_cap->link_cap->link_ptr); +NONCAP (&root_cap->link_ptr->link_ptr); +CAP (&root_ptr->link_cap->link_ptr); +NONCAP (&root_ptr->link_ptr->link_ptr); +CAP (&root_var.link_cap->link_ptr); +NONCAP (&root_var.link_ptr->link_ptr); +CAP (&root_arr->link_cap->link_ptr); +NONCAP (&root_arr->link_ptr->link_ptr); +CAP (&root_arr[0].link_cap->link_ptr); +NONCAP (&root_arr[0].link_ptr->link_ptr);