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).