public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] cp: Flesh out intcap handling
@ 2022-06-13 10:14 Alex Coplan
  0 siblings, 0 replies; only message in thread
From: Alex Coplan @ 2022-06-13 10:14 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:a70f0b0b24f1a3eb48bcf0d93e8ed7acee95481c

commit a70f0b0b24f1a3eb48bcf0d93e8ed7acee95481c
Author: Alex Coplan <alex.coplan@arm.com>
Date:   Wed Jun 8 12:52:29 2022 +0100

    cp: Flesh out intcap handling
    
    This patch ports some intcap tests from the Morello testsuite to C++ and
    adds all the missing handling to the C++ FE in order for the tests to
    pass. We also add a C++ testsuite directory and corresponding driver for
    Morello.
    
    gcc/c-family/ChangeLog:
    
            * c-common.c (binary_op_get_intcap_provenance): Also handle
            SPACESHIP_EXPR.
            (intcap_increment): New (moved from c-typeck.c).
            * c-common.h (intcap_increment): New.
    
    gcc/c/ChangeLog:
    
            * c-typeck.c (intcap_increment): Delete (move to c-common.c).
    
    gcc/ChangeLog:
    
            * convert.c (convert_to_real_1): Handle INTCAP_TYPE.
    
    gcc/cp/ChangeLog:
    
            * call.c (build_converted_constant_expr_internal): Handle
            INTCAP_TYPE.
            (build_conditional_expr_1): Likewise.
            * cp-tree.h (WANT_INTCAP): New.
            (cp_build_binary_op): Add new default-false parameter to
            suppress provenance warnings.
            * cvt.c (build_expr_type_conversion): Handle INTCAP_TYPE.
            * decl.c (compute_array_index_type_loc): Likewise.
            * typeck.c (cp_common_type): Port fix from C frontend to handle
            both types being INTCAP_TYPEs.
            (type_after_usual_arithmetic_conversions): Handle INTCAP_TYPE.
            (structural_comptypes): Likewise.
            (cp_build_binary_op): Use binary_op_get_intcap_provenance to
            determine provenance up front, ensure INTCAP_TYPE operands are
            not evaluated twice when this is unsafe.
            (cp_build_unary_op): Likewise; fix up INTCAP_TYPE handling.
            (cp_build_modify_expr): Suppress provenance warnings for
            self-modifying operators.
    
    gcc/testsuite/ChangeLog:
    
            * g++.target/aarch64/morello/intcap-semantics.C: New test.
            * g++.target/aarch64/morello/intcap-valid.C: New test.
            * g++.target/aarch64/morello/morello-cxx.exp: New test.

Diff:
---
 gcc/c-family/c-common.c                            |  33 ++++
 gcc/c-family/c-common.h                            |   3 +
 gcc/c/c-typeck.c                                   |  31 ---
 gcc/convert.c                                      |   3 +
 gcc/cp/call.c                                      |   5 +-
 gcc/cp/cp-tree.h                                   |   4 +-
 gcc/cp/cvt.c                                       |   5 +
 gcc/cp/decl.c                                      |   3 +
 gcc/cp/typeck.c                                    | 127 ++++++------
 .../g++.target/aarch64/morello/intcap-semantics.C  | 216 +++++++++++++++++++++
 .../g++.target/aarch64/morello/intcap-valid.C      |  84 ++++++++
 .../g++.target/aarch64/morello/morello-cxx.exp     |  42 ++++
 12 files changed, 465 insertions(+), 91 deletions(-)

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 212d48e6eaa..fed39e74f11 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -5216,6 +5216,7 @@ binary_op_get_intcap_provenance (location_t loc,
     case TRUTH_AND_EXPR:
     case TRUTH_OR_EXPR:
     case TRUTH_XOR_EXPR:
+    case SPACESHIP_EXPR:
       return NULL_TREE;
     case RSHIFT_EXPR:
     case LSHIFT_EXPR:
@@ -5326,6 +5327,38 @@ boolean_increment (enum tree_code code, tree arg)
   TREE_SIDE_EFFECTS (val) = 1;
   return val;
 }
+
+/* Like boolean_increment, but where ARG is of INTCAP_TYPE.  */
+tree
+intcap_increment (location_t loc, tree_code code, tree arg)
+{
+  tree t, cv, intcap, lval;
+
+  arg = lval = stabilize_reference (arg);
+  intcap = unary_op_get_intcap_provenance (arg);
+  if (intcap == arg)
+    /* This save_expr is needed to avoid evaluating
+       the intcap twice when we compute the REPLACE_ADDRESS_VALUE.  */
+    intcap = arg = save_expr (intcap);
+  cv = drop_capability (arg);
+
+  int dir = (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) ? 1 : -1;
+  t = build_int_cst (TREE_TYPE (cv), dir);
+  t = build2 (PLUS_EXPR, TREE_TYPE (cv), cv, t);
+  t = build_replace_address_value_loc (loc, intcap, t);
+  t = build2 (MODIFY_EXPR, TREE_TYPE (t), lval, t);
+
+  if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
+    {
+      /* This save_expr is needed to remember the original value.  */
+      arg = save_expr (arg);
+      t = build2 (COMPOUND_EXPR, TREE_TYPE (t), t, arg);
+      t = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t);
+    }
+
+  TREE_SIDE_EFFECTS (t) = 1;
+  return t;
+}
 \f
 /* Built-in macros for stddef.h and stdint.h, that require macros
    defined in this file.  */
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index d7f74732e09..4fdf78496ca 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1020,6 +1020,9 @@ extern tree unary_op_get_intcap_provenance (tree);
 /* Handle increment and decrement of boolean types.  */
 extern tree boolean_increment (enum tree_code, tree);
 
+/* Likewise for intcap types.  */
+extern tree intcap_increment (location_t loc, enum tree_code, tree);
+
 extern int case_compare (splay_tree_key, splay_tree_key);
 
 extern tree c_add_case_label (location_t, splay_tree, tree, tree, tree);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index f572b0607be..0195114a3b2 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -4353,37 +4353,6 @@ cas_loop:
 		 return_old_p ? old : newval);
 }
 
-static tree
-intcap_increment (location_t loc, tree_code code, tree arg)
-{
-  tree t, cv, intcap, lval;
-
-  arg = lval = stabilize_reference (arg);
-  intcap = unary_op_get_intcap_provenance (arg);
-  if (intcap == arg)
-    /* This save_expr is needed to avoid evaluating
-       the intcap twice when we compute the REPLACE_ADDRESS_VALUE.  */
-    intcap = arg = save_expr (intcap);
-  cv = drop_capability (arg);
-
-  int dir = (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) ? 1 : -1;
-  t = build_int_cst (TREE_TYPE (cv), dir);
-  t = build2 (PLUS_EXPR, TREE_TYPE (cv), cv, t);
-  t = build_replace_address_value_loc (loc, intcap, t);
-  t = build2 (MODIFY_EXPR, TREE_TYPE (t), lval, t);
-
-  if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
-    {
-      /* This save_expr is needed to remember the original value.  */
-      arg = save_expr (arg);
-      t = build2 (COMPOUND_EXPR, TREE_TYPE (t), t, arg);
-      t = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t);
-    }
-
-  TREE_SIDE_EFFECTS (t) = 1;
-  return t;
-}
-
 /* Construct and perhaps optimize a tree representation
    for a unary operation.  CODE, a tree_code, specifies the operation
    and XARG is the operand.
diff --git a/gcc/convert.c b/gcc/convert.c
index 347f44c4ace..e076be027f4 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -360,6 +360,9 @@ convert_to_real_1 (tree type, tree expr, bool fold_p)
 			  || DECIMAL_FLOAT_TYPE_P (itype))
 			 ? CONVERT_EXPR : NOP_EXPR, type, expr);
 
+    case INTCAP_TYPE:
+      expr = convert (noncapability_type (TREE_TYPE (expr)), expr);
+      /* FALLTHROUGH.  */
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index e56b56ac0f2..3e151788d7b 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4395,7 +4395,8 @@ build_converted_constant_expr_internal (tree type, tree expr,
 	case ck_ptr:
 	case ck_std:
 	  t = next_conversion (c)->type;
-	  if (INTEGRAL_OR_ENUMERATION_TYPE_P (t)
+	  if ((INTEGRAL_OR_ENUMERATION_TYPE_P (t)
+	       || INTCAP_TYPE_P (t))
 	      && INTEGRAL_OR_ENUMERATION_TYPE_P (type))
 	    /* Integral promotion or conversion.  */
 	    break;
@@ -5612,8 +5613,10 @@ build_conditional_expr_1 (const op_location_t &loc,
        type; the usual arithmetic conversions are performed to bring
        them to a common type, and the result is of that type.  */
   else if ((ARITHMETIC_TYPE_P (arg2_type)
+	    || INTCAP_TYPE_P (arg2_type)
 	    || UNSCOPED_ENUM_P (arg2_type))
 	   && (ARITHMETIC_TYPE_P (arg3_type)
+	       || INTCAP_TYPE_P (arg3_type)
 	       || UNSCOPED_ENUM_P (arg3_type)))
     {
       /* In this case, there is always a common type.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index af71fac2441..b9bbdd05a93 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5650,6 +5650,7 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 #define WANT_POINTER	8 /* pointer types */
 #define WANT_NULL      16 /* null pointer constant */
 #define WANT_VECTOR_OR_COMPLEX 32 /* vector or complex types */
+#define WANT_INTCAP	64 /* intcap types */
 #define WANT_ARITH	(WANT_INT | WANT_FLOAT | WANT_VECTOR_OR_COMPLEX)
 
 /* Used with comptypes, and related functions, to guide type
@@ -7615,7 +7616,8 @@ extern tree spaceship_type			(tree, tsubst_flags_t = tf_warning_or_error);
 extern tree genericize_spaceship		(tree, tree, tree);
 extern tree cp_build_binary_op                  (const op_location_t &,
 						 enum tree_code, tree, tree,
-						 tsubst_flags_t);
+						 tsubst_flags_t,
+						 bool = false);
 extern tree build_x_vec_perm_expr               (location_t,
 						 tree, tree, tree,
 						 tsubst_flags_t);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 83ec3aff0b3..6b0e3f7d2fb 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -1795,6 +1795,11 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
   if (! MAYBE_CLASS_TYPE_P (basetype))
     switch (TREE_CODE (basetype))
       {
+      case INTCAP_TYPE:
+	if (desires & WANT_INTCAP)
+	  return expr;
+	expr = drop_capability (expr);
+	/* fall through.  */
       case INTEGER_TYPE:
 	if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
 	  return expr;
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b647e925ab7..62c97d3447c 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10366,6 +10366,9 @@ compute_array_index_type_loc (location_t name_loc, tree name, tree size,
       if (error_operand_p (size))
 	return error_mark_node;
 
+      if (INTCAP_TYPE_P (TREE_TYPE (size)))
+	size = drop_capability (size);
+
       /* The array bound must be an integer type.  */
       tree type = TREE_TYPE (size);
       if (!INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type))
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index dc3fe39d941..b2a4566a67d 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -327,12 +327,11 @@ cp_common_type (tree t1, tree t2)
     return build_type_attribute_variant (t2, attributes);
 
   /* INTCAP_TYPEs out-rank all other integer types.  */
-  if ((code1 == INTCAP_TYPE && code2 != INTCAP_TYPE)
-      || (code2 == INTCAP_TYPE && code1 != INTCAP_TYPE))
+  if (code1 == INTCAP_TYPE || code2 == INTCAP_TYPE)
     {
       tree t_intcap = (code1 == INTCAP_TYPE) ? t1 : t2;
       tree t_int = (t_intcap == t1) ? t2 : t1;
-      gcc_assert (INTEGRAL_TYPE_P (t_int));
+      gcc_assert (INTEGRAL_TYPE_P (t_int) || INTCAP_TYPE_P (t_int));
 
       /* Note that the intcap always out-ranks the integer type, the only
 	 interesting case is therefore when the intcap is signed, the integer is
@@ -343,7 +342,7 @@ cp_common_type (tree t1, tree t2)
 	 to the unsigned integer type corresponding to the type of the operand
 	 with the signed integer type.  */
       if (!TYPE_UNSIGNED (t_intcap) && TYPE_UNSIGNED (t_int)
-	  && TYPE_NONCAP_PRECISION (t_intcap) <= TYPE_PRECISION (t_int))
+	  && TYPE_NONCAP_PRECISION (t_intcap) <= TYPE_NONCAP_PRECISION (t_int))
 	return uintcap_type_node;
       else
 	return t_intcap;
@@ -456,9 +455,11 @@ tree
 type_after_usual_arithmetic_conversions (tree t1, tree t2)
 {
   gcc_assert (ARITHMETIC_TYPE_P (t1)
+	      || INTCAP_TYPE_P (t1)
 	      || VECTOR_TYPE_P (t1)
 	      || UNSCOPED_ENUM_P (t1));
   gcc_assert (ARITHMETIC_TYPE_P (t2)
+	      || INTCAP_TYPE_P (t2)
 	      || VECTOR_TYPE_P (t2)
 	      || UNSCOPED_ENUM_P (t2));
 
@@ -1359,6 +1360,14 @@ structural_comptypes (tree t1, tree t2, int strict)
 	 track of equivalence in this case, so we fall back on it.  */
       return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
 
+    case INTCAP_TYPE:
+      /* There are only two INTCAP_TYPEs, identified by their
+	 signedness.  */
+      gcc_assert (TYPE_CAP_PRECISION (t1) == TYPE_CAP_PRECISION (t2));
+      if (TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
+	return false;
+      break;
+
     case TEMPLATE_TEMPLATE_PARM:
     case BOUND_TEMPLATE_TEMPLATE_PARM:
       if (!comp_template_parms_position (t1, t2))
@@ -4476,7 +4485,8 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain)
 tree
 cp_build_binary_op (const op_location_t &location,
 		    enum tree_code code, tree orig_op0, tree orig_op1,
-		    tsubst_flags_t complain)
+		    tsubst_flags_t complain,
+		    bool op0_provenance_p)
 {
   tree op0, op1;
   enum tree_code code0, code1;
@@ -4568,6 +4578,20 @@ cp_build_binary_op (const op_location_t &location,
   STRIP_TYPE_NOPS (op0);
   STRIP_TYPE_NOPS (op1);
 
+  tree intcap = binary_op_get_intcap_provenance (location, code, op0, op1,
+						 !op0_provenance_p);
+
+  /* If we will derive an intcap from either the LHS or the RHS,
+     wrap it with save_expr.  This will prevent us re-evaluating
+     any side effects of the intcap which will appear twice
+     in the resulting expression.  E.g. for
+     c + cv --> REPLACE_ADDRESS_VALUE (c, (non-cap type) c + cv)
+     we need to avoid evaluating c twice.  */
+  if (intcap == op0)
+    intcap = op0 = save_expr (op0);
+  else if (intcap == op1)
+    intcap = op1 = save_expr (op1);
+
   if (INTCAP_TYPE_P (TREE_TYPE (op0)))
     op0 = drop_capability (op0);
   if (INTCAP_TYPE_P (TREE_TYPE (op1)))
@@ -5842,56 +5866,15 @@ cp_build_binary_op (const op_location_t &location,
 
   /* For INTCAP_TYPEs, we dropped the capabilities early on and now need
      to work out where the provenance (if any) should come from.  */
-  if (!capability_type_p (TREE_TYPE (result))
-      && TREE_CODE_CLASS (code) != tcc_comparison
-      && code != SPACESHIP_EXPR
-      && result_type != boolean_type_node)
+  if (intcap)
     {
-      tree orig_type0 = TREE_TYPE (orig_op0);
-      tree orig_type1 = TREE_TYPE (orig_op1);
-
-      bool ic0 = INTCAP_TYPE_P (orig_type0);
-      bool ic1 = INTCAP_TYPE_P (orig_type1);
-
-      /* These flags are set if we need an intcap result type because of
-	 either the left or right operand respectively.  */
-      bool need_ic0 = ic0 && code1 == INTEGER_TYPE;
-      bool need_ic1 = ic1 && !doing_shift && code0 == INTEGER_TYPE;
-
-      bool prov0 = need_ic0
-	&& !lookup_attribute ("cheri_no_provenance",
-			      TYPE_ATTRIBUTES (orig_type0));
-      bool prov1 = need_ic1
-	&& !lookup_attribute ("cheri_no_provenance",
-			      TYPE_ATTRIBUTES (orig_type1));
-
-      tree intcap = nullptr;
-      if (prov0)
-	intcap = orig_op0;
-      else if (prov1)
-	intcap = orig_op1;
-      else if (need_ic0)
-	intcap = build_int_cst (orig_type0, 0);
-      else if (need_ic1)
-	intcap = build_int_cst (orig_type1, 0);
-
-      if (intcap)
-	{
-	  tree ic_type = cp_common_type (TREE_TYPE (intcap),
-					 TREE_TYPE (result));
-	  gcc_assert (same_type_p (TREE_TYPE (result), noncapability_type (ic_type)));
-	  intcap = cp_convert (ic_type, intcap, complain);
-	  result = fold_build_replace_address_value_loc (location,
-							 intcap,
-							 result);
-	}
-
-      if (prov0 && prov1)
-	warning_at (location, OPT_Wcheri_provenance,
-		    "binary expression on capability types %qT and %qT; "
-		    "it is not clear which should be the source of provenance; "
-		    "currently provenance is inherited from the left-hand side",
-		    orig_type0, orig_type1);
+      gcc_assert (!capability_type_p (TREE_TYPE (result)));
+      tree ic_type = cp_common_type (TREE_TYPE (intcap), TREE_TYPE (result));
+      gcc_assert (same_type_p (TREE_TYPE (result), noncapability_type (ic_type)));
+      intcap = cp_convert (ic_type, intcap, complain);
+      result = build_replace_address_value_loc (location,
+						intcap,
+						result);
     }
 
   if (instrument_expr != NULL)
@@ -6600,6 +6583,27 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert,
       return error_mark_node;
     }
 
+  tree intcap = NULL_TREE;
+  if (INTCAP_TYPE_P (TREE_TYPE (arg)))
+    {
+      switch (code)
+	{
+	CASE_ADDR_EXPR:
+	case UNARY_PLUS_EXPR:
+	case PREINCREMENT_EXPR:
+	case POSTINCREMENT_EXPR:
+	case PREDECREMENT_EXPR:
+	case POSTDECREMENT_EXPR:
+	case TRUTH_NOT_EXPR:
+	  break;
+	default:
+	  intcap = unary_op_get_intcap_provenance (arg);
+	  if (arg == intcap)
+	    intcap = arg = save_expr (arg);
+	  arg = drop_capability (arg);
+	}
+    }
+
   switch (code)
     {
     case UNARY_PLUS_EXPR:
@@ -6608,7 +6612,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert,
 	int flags = WANT_ARITH | WANT_ENUM;
 	/* Unary plus (but not unary minus) is allowed on pointers.  */
 	if (code == UNARY_PLUS_EXPR)
-	  flags |= WANT_POINTER;
+	  flags |= (WANT_POINTER | WANT_INTCAP);
 	arg = build_expr_type_conversion (flags, arg, true);
 	if (!arg)
 	  errstring = (code == NEGATE_EXPR
@@ -6729,7 +6733,9 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert,
 
       /* Report invalid types.  */
 
-      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_POINTER,
+      if (!(arg = build_expr_type_conversion (WANT_ARITH
+					      | WANT_POINTER
+					      | WANT_INTCAP,
 					      arg, true)))
 	{
 	  if (code == PREINCREMENT_EXPR)
@@ -6880,6 +6886,8 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert,
 	      }
 	    val = boolean_increment (code, arg);
 	  }
+	else if (TREE_CODE (declared_type) == INTCAP_TYPE)
+	  val = intcap_increment (location, code, arg);
 	else if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
 	  /* An rvalue has no cv-qualifiers.  */
 	  val = build2 (code, cv_unqualified (TREE_TYPE (arg)), arg, inc);
@@ -6903,7 +6911,10 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert,
     {
       if (argtype == 0)
 	argtype = TREE_TYPE (arg);
-      return build1 (code, argtype, arg);
+      arg = build1 (code, argtype, arg);
+      if (intcap)
+	arg = build_replace_address_value_loc (location, intcap, arg);
+      return arg;
     }
 
   if (complain & tf_error)
@@ -8740,7 +8751,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
 	  if (rhs == error_mark_node)
 	    return error_mark_node;
 	  rhs = stabilize_expr (rhs, &init);
-	  newrhs = cp_build_binary_op (loc, modifycode, lhs, rhs, complain);
+	  newrhs = cp_build_binary_op (loc, modifycode, lhs, rhs, complain, true);
 	  if (newrhs == error_mark_node)
 	    {
 	      if (complain & tf_error)
diff --git a/gcc/testsuite/g++.target/aarch64/morello/intcap-semantics.C b/gcc/testsuite/g++.target/aarch64/morello/intcap-semantics.C
new file mode 100644
index 00000000000..081d85fad69
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/intcap-semantics.C
@@ -0,0 +1,216 @@
+/* Check that intcap semantics are implemented correctly in the
+   front-end.  */
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-original" } */
+
+__intcap f1(__intcap x1, long y1)
+{
+  return x1 + y1;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x1>, \(long int\) SAVE_EXPR <x1> \+ y1\)} 1 "original"  } } */
+
+__intcap f2(__intcap x2, int y2)
+{
+  return x2 + y2;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x2>, \(long int\) SAVE_EXPR <x2> \+ \(long int\) y2\)} 1 "original"  } } */
+
+__intcap f3(__intcap x3, short y3)
+{
+  return x3 + y3;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x3>, \(long int\) SAVE_EXPR <x3> \+ \(long int\) y3\)} 1 "original"  } } */
+
+__intcap f4(__intcap x4, unsigned int y4)
+{
+  return x4 + y4;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x4>, \(long int\) SAVE_EXPR <x4> \+ \(long int\) y4\)} 1 "original"  } } */
+
+unsigned __intcap f5(__intcap x5, unsigned long y5)
+{
+  return x5 + y5;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(\(unsigned __intcap\) SAVE_EXPR <x5>, \(long unsigned int\) SAVE_EXPR <x5> \+ y5\)} 1 "original"  } } */
+
+unsigned __intcap f6(unsigned __intcap x6, unsigned long y6)
+{
+  return x6 + y6;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x6>, \(long unsigned int\) SAVE_EXPR <x6> \+ y6\)} 1 "original"  } } */
+
+unsigned __intcap f7(unsigned __intcap x7, long y7)
+{
+  return x7 + y7;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x7>, \(long unsigned int\) SAVE_EXPR <x7> \+ \(long unsigned int\) y7\)} 1 "original"  } } */
+
+bool f8(__intcap x8, __intcap y8)
+{
+  return x8 > y8;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \(long int\) x8 > \(long int\) y8;} 1 "original"  } } */
+
+bool f9(unsigned __intcap x9, __intcap y9)
+{
+  return x9 > y9;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \(long unsigned int\) x9 > \(long unsigned int\) y9;} 1 "original"  } } */
+
+__intcap f10 (long x10)
+{
+  return (__intcap)x10;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(0, x10\);} 1 "original"  } } */
+
+char * __capability f11 (char * __capability x11, __intcap y11)
+{
+  return x11 + y11;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = x11 \+ \(sizetype\) y11;} 1 "original"  } } */
+
+float f12(__intcap x12, float y12)
+{
+  return x12 + y12;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \(float\) \(long int\) x12 \+ y12;} 1 "original"  } } */
+
+__intcap f13(__intcap x13)
+{
+  return +x13;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = NON_LVALUE_EXPR <x13>;} 1 "original"  } } */
+
+__intcap f14(__intcap x14)
+{
+  return -x14;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x14>, -\(long int\) SAVE_EXPR <x14>\)} 1 "original"  } } */
+
+__intcap f15(__intcap x15)
+{
+  return ~x15;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x15>, ~\(long int\) SAVE_EXPR <x15>\)} 1 "original"  } } */
+
+bool f16(__intcap x16)
+{
+  return !x16;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \(long int\) x16 == 0;} 1 "original"  } } */
+
+__intcap gc;
+__intcap *f17 ()
+{
+  return &gc;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = &gc;} 1 "original"  } } */
+
+__intcap f18 (__intcap x18 __attribute__((cheri_no_provenance)), __intcap y18)
+{
+  return x18 + y18;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <y18>, \(long int\) x18 \+ \(long int\) SAVE_EXPR <y18>\)} 1 "original"  } } */
+
+__intcap f19 (__intcap x19,
+	      __intcap y19 __attribute__((cheri_no_provenance)))
+{
+  return x19 + y19;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x19>, \(long int\) SAVE_EXPR <x19> \+ \(long int\) y19\)} 1 "original"  } } */
+
+__intcap f20 (__intcap x20 __attribute__((cheri_no_provenance)),
+	      __intcap y20 __attribute__((cheri_no_provenance)))
+{
+  return x20 + y20;
+}
+
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(0, \(long int\) x20 \+ \(long int\) y20\)} 1 "original"  } } */
+
+unsigned __intcap f21 (unsigned __intcap __attribute__((cheri_no_provenance))
+		       x21,
+		       __intcap __attribute__((cheri_no_provenance)) y21)
+{
+  return x21 + y21;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(0, \(long unsigned int\) x21 \+ \(long unsigned int\) y21\)} 1 "original"  } } */
+
+unsigned __intcap f22 (__intcap __attribute__((cheri_no_provenance)) x22,
+		       unsigned __intcap __attribute__((cheri_no_provenance))
+		       y22)
+{
+  return x22 + y22;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(0, \(long unsigned int\) x22 \+ \(long unsigned int\) y22\)} 1 "original"  } } */
+
+unsigned __intcap f23 (unsigned __intcap
+		       __attribute__ ((cheri_no_provenance)) x23,
+		       unsigned __intcap
+		       __attribute__ ((cheri_no_provenance)) y23)
+{
+  return x23 + y23;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(0, \(long unsigned int\) x23 \+ \(long unsigned int\) y23\)} 1 "original"  } } */
+
+__intcap f24 (__intcap __attribute__((cheri_no_provenance)) x24)
+{
+  return x24 + 1;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(0, \(long int\) x24 \+ 1\);} 1 "original"  } } */
+
+__intcap f25 (__intcap __attribute__ ((cheri_no_provenance)) x25)
+{
+  return -x25;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(0, -\(long int\) x25\);} 1 "original"  } } */
+
+__intcap x26;
+__intcap f26() {
+    return x26++;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = SAVE_EXPR <x26>;, x26 = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x26>, \(long int\) SAVE_EXPR <x26> \+ 1\);, SAVE_EXPR <x26>;} 1 "original"  } } */
+
+__intcap x27;
+__intcap f27() {
+    return ++x27;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = x27 = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x27>, \(long int\) SAVE_EXPR <x27> \+ 1\)} 1 "original"  } } */
+
+__intcap x28 __attribute__((cheri_no_provenance));
+__intcap f28() {
+    return --x28;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = x28 = \.REPLACE_ADDRESS_VALUE \(0, \(long int\) x28 \+ -1\)} 1 "original"  } } */
+
+__intcap x29 __attribute__((cheri_no_provenance));
+__intcap f29()
+{
+  return x29++;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = SAVE_EXPR <x29>;, x29 = \.REPLACE_ADDRESS_VALUE \(0, \(long int\) x29 \+ 1\);, SAVE_EXPR <x29>;} 1 "original"  } } */
+
+__intcap f30(__intcap x30,
+	     __intcap y30)
+{
+  return x30 + y30; /* { dg-warning "it is not clear which should be used as the source of provenance" } */
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x30>, \(long int\) SAVE_EXPR <x30> \+ \(long int\) y30\)} 1 "original"  } } */
+
+__intcap x31, y31;
+void f31()
+{
+  x31 += y31;
+}
+/* { dg-final { scan-tree-dump-times {x31 = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x31>, \(long int\) SAVE_EXPR <x31> \+ \(long int\) y31\)} 1 "original"  } } */
+
+__intcap f32 (__intcap x32, __intcap y32)
+{
+  return x32 << y32;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x32>, \(long int\) SAVE_EXPR <x32> << \(long int\) y32\)} 1 "original"  } } */
+
+bool f33 (__intcap x33, __intcap y33)
+{
+  return x33 || y33;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \(long int\) x33 != 0 \|\| \(long int\) y33 != 0;} 1 "original"  } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/intcap-valid.C b/gcc/testsuite/g++.target/aarch64/morello/intcap-valid.C
new file mode 100644
index 00000000000..76e9355614c
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/intcap-valid.C
@@ -0,0 +1,84 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-Werror" } */
+
+__intcap_t ptr_to_intcap_cast(int *x) { return (__intcap_t)x; }
+int *intcap_to_ptr_cast(__intcap_t x) { return (int *)x; }
+
+int *null_pointer(void) { return (int *)0; }
+__intcap_t int_to_intcap_cast(int x) { return (__intcap_t)x; }
+
+__intcap_t intcap_zero(void) { return 0; }
+__intcap_t intcap_one(void) { return 1; }
+__intcap_t intcap_of_int(int x) { return x; }
+long long_of_intcap(__intcap_t x) { return x; }
+__intcap_t intcap_of_long(long x) { return x; }
+double dbl_of_intcap(__intcap_t x) { return x; }
+__intcap_t intcap_of_dbl(double x) { return x; }
+bool bool_of_intcap(__intcap_t x) { return x; }
+__intcap_t intcap_of_bool(bool x) { return x; }
+
+char *ptr_add_intcap(char *p, __intcap_t x) { return p + x; }
+char *ptr_sub_intcap(char *p, __intcap_t x) { return p - x; }
+__intcap_t intcap_add_int(__intcap_t c, int i) { return c + i; }
+__intcap_t intcap_add_one(__intcap_t c) { return c + 1; }
+__intcap_t intcap_sub_int(__intcap_t c, int i) { return c - i; }
+__intcap_t intcap_sub_one(__intcap_t c) { return c - 1; }
+float add_intcap_float(__intcap_t c, float f) { return c + f; }
+
+__intcap_t intcap_and(__intcap_t c, long x) { return c & x; }
+__intcap_t intcap_align(__intcap_t c) { return c & ~7; }
+
+int intcap_eq(__intcap_t a, __intcap_t b) { return a == b; }
+int incap_gt(__intcap_t a, __intcap_t b) { return a > b; }
+int incap_lt(__intcap_t a, __intcap_t b) { return a < b; }
+
+__intcap_t intcap_unplus(__intcap_t c) { return +c; }
+__intcap_t intcap_not(__intcap_t c) { return !c; }
+__intcap_t intcap_neg(__intcap_t c) { return -c; }
+__intcap_t intcap_inv(__intcap_t c) { return ~c; }
+
+void sink(void *p);
+void intcap_addrof(__intcap_t c) { sink(&c); }
+
+__intcap_t gc;
+__intcap_t intcap_postinc(__intcap_t c) { return gc++; }
+__intcap_t intcap_preinc(__intcap_t c) { return ++gc; }
+__intcap_t intcap_postdec(__intcap_t c) { return gc--; }
+__intcap_t intcap_predec(__intcap_t c) { return --gc; }
+
+int intcap_cast(__intcap_t c) { return (long)c; }
+int intcap_real(__intcap_t c) { return __real__ c; }
+
+__intcap_t cond2a(int a, long b, __intcap_t c) { return a ? b : c; }
+__intcap_t cond2b(int a, long b, __intcap_t c) { return a ? c : b; }
+float cond3a(int a, float b, __intcap_t c) { return a ? b : c; }
+float cond3b(int a, float b, __intcap_t c) { return a ? c : b; }
+__intcap_t cond4a(int a, bool b, __intcap_t c) { return a ? b : c; }
+
+__uintcap_t signed_to_unsigned(__intcap_t c) { return c; }
+__intcap_t unsigned_to_signed(__uintcap_t c) { return c; }
+__intcap_t intcap_add_u(__intcap_t c, unsigned x) { return c + x; }
+__uintcap_t intcap_add_ul(__intcap_t c, unsigned long x) { return c + x; }
+__uintcap_t uintcap_add_l(__uintcap_t c, long x) { return c + x; }
+__uintcap_t uintcap_add_ul(__uintcap_t c, unsigned long x) { return c + x; }
+
+__intcap_t intcap_shift(__intcap_t c, int x) { return c << x; }
+int shift_by_intcap(int x, __intcap_t c) { return x << c; }
+
+__intcap_t maybe_const_expr(__intcap_t c, int x) { return c + (x < 0); }
+void intcap_vla(__intcap_t c) { int a[c]; }
+
+int intcap_truth_or(__intcap_t c, int x) { return c || x; }
+
+/* N.B. provenance is clear here: it comes from the LHS.  */
+__intcap_t intcap_shift_intcap(__intcap_t a, __intcap_t b)
+{ return a << b; }
+
+int intcap_index(int *p, __intcap_t c) { return p[c]; }
+
+/* Note the self-modifying operators are considered to have unambiguous
+   provenance.  */
+__intcap x, y;
+void pluseq(void) { x += y; }
+void timeseq(void) { x *= y; }
+void modeq(void) { x %= y; }
diff --git a/gcc/testsuite/g++.target/aarch64/morello/morello-cxx.exp b/gcc/testsuite/g++.target/aarch64/morello/morello-cxx.exp
new file mode 100644
index 00000000000..0ffed8a3bfb
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/morello-cxx.exp
@@ -0,0 +1,42 @@
+#  Specific regression driver for AArch64 Morello.
+#  Copyright (C) 2022 Free Software Foundation, Inc.
+#
+#  This file is part of GCC.
+#
+#  GCC is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 3, or (at your option)
+#  any later version.
+#
+#  GCC is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with GCC; see the file COPYING3.  If not see
+#  <http://www.gnu.org/licenses/>.  */
+
+# Exit immediately if this isn't an AArch64 target.
+if {![istarget aarch64*-*-*] } then {
+  return
+}
+
+# Load support procs.
+load_lib g++-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+if { [check_effective_target_aarch64_capability_any] } {
+  set capability_flags ""
+} else {
+  set capability_flags "-mfake-capability"
+}
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \
+    "" "$capability_flags"
+
+# All done.
+dg-finish


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-06-13 10:14 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-13 10:14 [gcc(refs/vendors/ARM/heads/morello)] cp: Flesh out intcap handling Alex Coplan

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