public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] c: Propagate capability-ness through &addr->foo etc.
@ 2022-05-05 12:09 Matthew Malcomson
0 siblings, 0 replies; only message in thread
From: Matthew Malcomson @ 2022-05-05 12:09 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:3c8cbe08bea173f7878b2313c353d7bdcea920e5
commit 3c8cbe08bea173f7878b2313c353d7bdcea920e5
Author: Richard Sandiford <richard.sandiford@arm.com>
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<tree, va_gc> *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<tree, va_gc> *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);
+}
\f
/* 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);
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-05-05 12:09 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-05 12:09 [gcc(refs/vendors/ARM/heads/morello)] c: Propagate capability-ness through &addr->foo etc Matthew Malcomson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).