public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] c: Fix up INTCAP_TYPE semantics
@ 2022-05-20 10:42 Alex Coplan
  0 siblings, 0 replies; only message in thread
From: Alex Coplan @ 2022-05-20 10:42 UTC (permalink / raw)
  To: gcc-cvs

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

commit d7f8b9c884e6543aefe40c13fdd19f4caa997026
Author: Alex Coplan <alex.coplan@arm.com>
Date:   Mon May 16 11:56:33 2022 +0100

    c: Fix up INTCAP_TYPE semantics
    
    This patch adds a test which scans the output of -fdump-tree-original on
    various interesting cases involving __intcap to ensure we implement the
    expected semantics. We then fix up various issues that fell out of this
    testing. It is hoped that the test can later be used in the C++ FE with only
    minor modifications.
    
    Issues fixed by the patch in brief:
     - Duplicate INTCAP_TYPE nodes in the IR.
     - Unary plus: don't build a RAV.
     - Canonicalize INTCAP_TYPEs with cheri_no_provenance (don't propagate the
       attribute).
     - Self-modifying operators have unambiguous provenance.
    
    Some of the tests revealed unexpected (seemingly no-op) conversions were
    being inserted by the C FE. This issue turned out to have two causes:
     1. INTCAP_TYPEs were not being hashed and cached properly.
     2. cheri_no_provenance attributes were leaking through to places where
        they shouldn't be.
    
    The first issue was resolved by teaching type_cache_hasher::equal about
    INTCAP_TYPEs. We also tweak build_intcap_type_for_mode to ensure that
    the nodes we cache there are also the nodes cached by type_hash_canon.
    This gives us the nice property that there are exactly two canonical
    (i.e. unadorned) INTCAP_TYPE nodes in the IR.
    
    The second issue is fixed by calling build_type_attribute_variant to
    strip the cheri_no_provenance attribute from the result type of an
    expression involving operands with cheri_no_provenance-annotated
    INTCAP_TYPE operands. This ensures we always end up ascribing a
    canonical INTCAP_TYPE to expressions of INTCAP_TYPE, and avoids spurious
    conversions seen in the new intcap-semantics.c test.
    
    We adjust the handling of unary plus to avoid building a redundant
    REPLACE_ADDRESS_VALUE for this operator on INTCAP_TYPE operands.
    
    We also adjust the handling of self-modifying operators (e.g. +=) on
    INTCAP_TYPE operands. CHERI LLVM considers these to be unambiguous (with
    provenance coming from the LHS), which seems like a reasonable
    heuristic, so we implement this behaviour here.
    
    gcc/c/ChangeLog:
    
            * c-typeck.c (build_binary_op_1): New.
            (c_build_replace_address_value_1): New.
            (c_build_replace_address_value): New.
            (c_fold_build_replace_address_value): New. Use it ...
            (intcap_increment): ... here ...
            (build_unary_op): ... and here. Don't build a REPLACE_ADDRESS_VALUE for
            CONVERT_EXPR (i.e. unary plus) on INTCAP_TYPEs: just use the
            usual handling to get a non-lvalue expression.
            (build_modify_expr): Call the new build_binary_op_1, asking for
            unambiguous provenance on self-modifying operators.
            (build_binary_op): Call build_binary_op_1.
    
    gcc/ChangeLog:
    
            * tree.c (type_cache_hasher::equal): Handle INTCAP_TYPEs.
            (build_intcap_type_for_mode): Call type_hash_canon and cache the
            node it returns such that either cache gives the same tree node.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/aarch64/morello/intcap-valid.c: Add tests involving
            self-modifying operators.
            * gcc.target/aarch64/morello/intcap-invalid.c: New test.
            * gcc.target/aarch64/morello/intcap-semantics.c: New test.

Diff:
---
 gcc/c/c-typeck.c                                   | 108 ++++++++---
 gcc/testsuite/gcc.dg/graphite/pr86479.c            |   1 -
 gcc/testsuite/gcc.dg/pr45733.c                     |   1 -
 .../gcc.target/aarch64/morello/intcap-invalid.c    |   5 +
 .../gcc.target/aarch64/morello/intcap-semantics.c  | 216 +++++++++++++++++++++
 .../gcc.target/aarch64/morello/intcap-valid.c      |   7 +
 gcc/tree.c                                         |  10 +
 7 files changed, 316 insertions(+), 32 deletions(-)

diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 5abdee5ed15..04a0528d6e8 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -124,6 +124,10 @@ static void readonly_warning (tree, enum lvalue_use);
 static int lvalue_or_else (location_t, const_tree, enum lvalue_use);
 static void record_maybe_used_decl (tree);
 static int comptypes_internal (const_tree, const_tree, bool *, bool *);
+static tree
+build_binary_op_1 (location_t location, enum tree_code code,
+		 tree orig_op0, tree orig_op1, bool convert_p,
+		 bool op0_provenance_p);
 \f
 /* Return true if EXP is a null pointer constant, false otherwise.  */
 
@@ -4349,6 +4353,36 @@ cas_loop:
 		 return_old_p ? old : newval);
 }
 
+static tree
+c_build_replace_address_value_1 (location_t loc, tree c, tree cv, bool fold)
+{
+  tree type = TREE_TYPE (c);
+  tree attrs = TYPE_ATTRIBUTES (type);
+  static const char * const cnp = "cheri_no_provenance";
+  if (lookup_attribute (cnp, attrs))
+    {
+      attrs = remove_attribute (cnp, attrs);
+      type = build_type_attribute_variant (type, attrs);
+      return c_common_cap_from_noncap (type, cv);
+    }
+
+  return fold
+    ? fold_build_replace_address_value_loc (loc, c, cv)
+    : build_replace_address_value_loc (loc, c, cv);
+}
+
+static tree
+c_build_replace_address_value (location_t loc, tree c, tree cv)
+{
+  return c_build_replace_address_value_1 (loc, c, cv, false);
+}
+
+static tree
+c_fold_build_replace_address_value (location_t loc, tree c, tree cv)
+{
+  return c_build_replace_address_value_1 (loc, c, cv, true);
+}
+
 static tree
 intcap_increment (location_t loc, tree_code code, tree arg)
 {
@@ -4360,20 +4394,14 @@ intcap_increment (location_t loc, tree_code code, tree 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);
-
-  if (lookup_attribute ("cheri_no_provenance",
-			TYPE_ATTRIBUTES (TREE_TYPE (arg))))
-    t = c_common_cap_from_noncap (TREE_TYPE (arg), t);
-  else
-    t = build_replace_address_value_loc (loc, arg, t);
-
-  t = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, t);
+  t = c_build_replace_address_value (loc, arg, t);
+  t = build2 (MODIFY_EXPR, TREE_TYPE (t), arg, t);
 
   if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
     {
       arg = save_expr (arg);
-      t = build2 (COMPOUND_EXPR, TREE_TYPE (arg), t, arg);
-      t = build2 (COMPOUND_EXPR, TREE_TYPE (arg), arg, t);
+      t = build2 (COMPOUND_EXPR, TREE_TYPE (t), t, arg);
+      t = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t);
     }
 
   TREE_SIDE_EFFECTS (t) = 1;
@@ -4417,6 +4445,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
       switch (code)
 	{
 	CASE_ADDR_EXPR:
+	case CONVERT_EXPR:
 	case PREINCREMENT_EXPR:
 	case POSTINCREMENT_EXPR:
 	case PREDECREMENT_EXPR:
@@ -4455,6 +4484,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
 	 associativity, but won't generate any code.  */
       if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
 	    || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE
+	    || typecode == INTCAP_TYPE
 	    || gnu_vector_type_p (TREE_TYPE (arg))))
 	{
 	  error_at (location, "wrong type argument to unary plus");
@@ -4931,13 +4961,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
 
   if (TREE_CODE (TREE_TYPE (xarg)) == INTCAP_TYPE
       && !capability_type_p (TREE_TYPE (ret)))
-    {
-      if (lookup_attribute ("cheri_no_provenance",
-			    TYPE_ATTRIBUTES (TREE_TYPE (xarg))))
-	ret = c_common_cap_from_noncap (TREE_TYPE (xarg), ret);
-      else
-	ret = fold_build_replace_address_value_loc (location, xarg, ret);
-    }
+    ret = c_fold_build_replace_address_value (location, xarg, ret);
 
  return_build_unary_op:
   gcc_assert (ret != error_mark_node);
@@ -6320,8 +6344,8 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
 		newrhs = build1 (EXCESS_PRECISION_EXPR, TREE_TYPE (rhs),
 				 newrhs);
 	    }
-	  newrhs = build_binary_op (location,
-				    modifycode, lhs, newrhs, true);
+	  newrhs = build_binary_op_1 (location,
+				      modifycode, lhs, newrhs, true, true);
 
 	  /* The original type of the right hand side is no longer
 	     meaningful.  */
@@ -11877,11 +11901,16 @@ build_vec_cmp (tree_code code, tree type,
    Note that the operands will never have enumeral types, or function
    or array types, because either they will have the default conversions
    performed or they have both just been converted to some other type in which
-   the arithmetic is to be done.  */
+   the arithmetic is to be done.
 
-tree
-build_binary_op (location_t location, enum tree_code code,
-		 tree orig_op0, tree orig_op1, bool convert_p)
+   OP0_PROVENANCE_P defaults to false when called from build_binary_op.
+   If set to true, we assume that any provenance comes from
+   ORIG_OP0 where it would otherwise be ambiguous.  */
+
+static tree
+build_binary_op_1 (location_t location, enum tree_code code,
+		 tree orig_op0, tree orig_op1, bool convert_p,
+		 bool op0_provenance_p)
 {
   tree type0, type1, orig_type0, orig_type1, nonic_type0, nonic_type1;
   tree eptype;
@@ -13090,11 +13119,12 @@ build_binary_op (location_t location, enum tree_code code,
       bool need_ic0 = ic0 && code1 == INTEGER_TYPE;
       bool need_ic1 = ic1 && !doing_shift && code0 == INTEGER_TYPE;
 
+      static const char * const cnp = "cheri_no_provenance";
       bool prov0 = need_ic0
-		   && !lookup_attribute ("cheri_no_provenance",
+		   && !lookup_attribute (cnp,
 					 TYPE_ATTRIBUTES (orig_type0));
       bool prov1 = need_ic1
-		   && !lookup_attribute ("cheri_no_provenance",
+		   && !lookup_attribute (cnp,
 					 TYPE_ATTRIBUTES (orig_type1));
 
       tree intcap = NULL;
@@ -13102,10 +13132,19 @@ build_binary_op (location_t location, enum tree_code code,
 	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);
+      else if (need_ic0 || need_ic1)
+	{
+	  tree type;
+	  if (need_ic0 && need_ic1)
+	    type = c_common_type (orig_type0, orig_type1);
+	  else
+	    {
+	      type = need_ic0 ? orig_type0 : orig_type1;
+	      tree attrs = remove_attribute (cnp, TYPE_ATTRIBUTES (type));
+	      type = build_type_attribute_variant (type, attrs);
+	    }
+	  intcap = build_int_cst (type, 0);
+	}
 
       if (intcap)
 	{
@@ -13120,7 +13159,7 @@ build_binary_op (location_t location, enum tree_code code,
 	  ret = fold_build_replace_address_value_loc (location, intcap, ret);
 	}
 
-	if (prov0 && prov1)
+	if (prov0 && prov1 && !op0_provenance_p)
 	  warning_at (location, OPT_Wcheri_provenance,
 	    "binary expression on capability types %qT and %qT; "
 	    "it is not clear which should be used as the source of provenance; "
@@ -13150,6 +13189,15 @@ build_binary_op (location_t location, enum tree_code code,
   return ret;
 }
 
+/* Implement c-common.h:build_binary_op by wrapping our internal
+   build_binary_op_1, setting the additional OP0_PROVENANCE_P
+   parameter to false.  */
+tree
+build_binary_op (location_t location, enum tree_code code,
+		 tree op0, tree op1, bool convert_p)
+{
+  return build_binary_op_1 (location, code, op0, op1, convert_p, false);
+}
 
 /* Convert EXPR to be a truth-value, validating its type for this
    purpose.  LOCATION is the source location for the expression.  */
diff --git a/gcc/testsuite/gcc.dg/graphite/pr86479.c b/gcc/testsuite/gcc.dg/graphite/pr86479.c
index 30d1837f8fd..7df63546c05 100644
--- a/gcc/testsuite/gcc.dg/graphite/pr86479.c
+++ b/gcc/testsuite/gcc.dg/graphite/pr86479.c
@@ -25,7 +25,6 @@ m7 (__INTPTR_TYPE__ *aw, __INTPTR_TYPE__ ws)
 
           ws /= cq;
           *aw *= ws;
-          /* { dg-warning "binary expression on capability types" "" { target { aarch64_capability_any } } .-1 } */
 
           for (*ud = 0; *ud < 2; ++*ud)
             {
diff --git a/gcc/testsuite/gcc.dg/pr45733.c b/gcc/testsuite/gcc.dg/pr45733.c
index 1757346c7db..5c83cd42ca5 100644
--- a/gcc/testsuite/gcc.dg/pr45733.c
+++ b/gcc/testsuite/gcc.dg/pr45733.c
@@ -9,6 +9,5 @@ foo (void **p, int i)
   intptr_t x = 0;
   while (i--)
     x ^= (intptr_t) p[i];
-    /* { dg-warning "binary expression on capability types" "" { target { aarch64_capability_any } } .-1 } */
   return x;
 }
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/intcap-invalid.c b/gcc/testsuite/gcc.target/aarch64/morello/intcap-invalid.c
new file mode 100644
index 00000000000..e2e0534ea88
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/intcap-invalid.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+void unary_plus_non_lvalue(__intcap c)
+{
+  +c = c; /* { dg-error "lvalue required as left operand of assignment" } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/intcap-semantics.c b/gcc/testsuite/gcc.target/aarch64/morello/intcap-semantics.c
new file mode 100644
index 00000000000..6f83dd91383
--- /dev/null
+++ b/gcc/testsuite/gcc.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 {return \.REPLACE_ADDRESS_VALUE \(x1, \(long int\) x1 \+ y1\)} 1 "original"  } } */
+
+__intcap f2(__intcap x2, int y2)
+{
+  return x2 + y2;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(x2, \(long int\) x2 \+ \(long int\) y2\)} 1 "original"  } } */
+
+__intcap f3(__intcap x3, short y3)
+{
+  return x3 + y3;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(x3, \(long int\) x3 \+ \(long int\) y3\)} 1 "original"  } } */
+
+__intcap f4(__intcap x4, unsigned int y4)
+{
+  return x4 + y4;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(x4, \(long int\) x4 \+ \(long int\) y4\)} 1 "original"  } } */
+
+unsigned __intcap f5(__intcap x5, unsigned long y5)
+{
+  return x5 + y5;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(\(unsigned __intcap\) x5, \(long unsigned int\) x5 \+ y5\)} 1 "original"  } } */
+
+unsigned __intcap f6(unsigned __intcap x6, unsigned long y6)
+{
+  return x6 + y6;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(x6, \(long unsigned int\) x6 \+ y6\)} 1 "original"  } } */
+
+unsigned __intcap f7(unsigned __intcap x7, long y7)
+{
+  return x7 + y7;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(x7, \(long unsigned int\) x7 \+ \(long unsigned int\) y7\)} 1 "original"  } } */
+
+_Bool f8(__intcap x8, __intcap y8)
+{
+  return x8 > y8;
+}
+/* { dg-final { scan-tree-dump-times {return \(long int\) x8 > \(long int\) y8;} 1 "original"  } } */
+
+_Bool f9(unsigned __intcap x9, __intcap y9)
+{
+  return x9 > y9;
+}
+/* { dg-final { scan-tree-dump-times {return \(long unsigned int\) x9 > \(long unsigned int\) y9;} 1 "original"  } } */
+
+__intcap f10 (long x10)
+{
+  return (__intcap)x10;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(0, x10\);} 1 "original"  } } */
+
+char * __capability f11 (char * __capability x11, __intcap y11)
+{
+  return x11 + y11;
+}
+/* { dg-final { scan-tree-dump-times {return x11 \+ \(sizetype\) y11;} 1 "original"  } } */
+
+float f12(__intcap x12, float y12)
+{
+  return x12 + y12;
+}
+/* { dg-final { scan-tree-dump-times {return \(float\) \(long int\) x12 \+ y12;} 1 "original"  } } */
+
+__intcap f13(__intcap x13)
+{
+  return +x13;
+}
+/* { dg-final { scan-tree-dump-times {return x13;} 1 "original"  } } */
+
+__intcap f14(__intcap x14)
+{
+  return -x14;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(x14, * -\(long int\) x14\);} 1 "original"  } } */
+
+__intcap f15(__intcap x15)
+{
+  return ~x15;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(x15, * ~\(long int\) x15\);} 1 "original"  } } */
+
+_Bool f16(__intcap x16)
+{
+  return !x16;
+}
+/* { dg-final { scan-tree-dump-times {return \(long int\) x16 == 0;} 1 "original"  } } */
+
+__intcap gc;
+__intcap *f17 (void)
+{
+  return &gc;
+}
+/* { dg-final { scan-tree-dump-times {return &gc;} 1 "original"  } } */
+
+__intcap f18 (__intcap x18 __attribute__((cheri_no_provenance)), __intcap y18)
+{
+  return x18 + y18;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(y18, \(long int\) x18 \+ \(long int\) y18\)} 1 "original"  } } */
+
+__intcap f19 (__intcap x19,
+	      __intcap y19 __attribute__((cheri_no_provenance)))
+{
+  return x19 + y19;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(x19, \(long int\) 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 {return \.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 {return \.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 {return \.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 {return \.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 {return \.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 {return \.REPLACE_ADDRESS_VALUE \(0, -\(long int\) x25\);} 1 "original"  } } */
+
+__intcap x26;
+__intcap f26(void) {
+    return x26++;
+}
+/* { dg-final { scan-tree-dump-times {return SAVE_EXPR <x26>;, x26 = \.REPLACE_ADDRESS_VALUE \(x26, \(long int\) x26 \+ 1\);, SAVE_EXPR <x26>;;} 1 "original"  } } */
+
+__intcap x27;
+__intcap f27(void) {
+    return ++x27;
+}
+/* { dg-final { scan-tree-dump-times {return x27 = \.REPLACE_ADDRESS_VALUE \(x27, \(long int\) x27 \+ 1\);} 1 "original"  } } */
+
+__intcap x28 __attribute__((cheri_no_provenance));
+__intcap f28(void) {
+    return --x28;
+}
+/* { dg-final { scan-tree-dump-times {return x28 = \.REPLACE_ADDRESS_VALUE \(0, \(long int\) x28 \+ -1\);} 1 "original"  } } */
+
+__intcap x29 __attribute__((cheri_no_provenance));
+__intcap f29(void)
+{
+  return x29++;
+}
+/* { dg-final { scan-tree-dump-times {return 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 {return \.REPLACE_ADDRESS_VALUE \(x30, \(long int\) x30 \+ \(long int\) y30\)} 1 "original"  } } */
+
+__intcap x31, y31;
+void f31(void)
+{
+  x31 += y31;
+}
+/* { dg-final { scan-tree-dump-times {x31 = \.REPLACE_ADDRESS_VALUE \(x31, \(long int\) x31 \+ \(long int\) y31\)} 1 "original"  } } */
+
+__intcap f32 (__intcap x32, __intcap y32)
+{
+  return x32 << y32;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(x32, \(long int\) x32 << \(long int\) y32\)} 1 "original"  } } */
+
+int f33 (__intcap x33, __intcap y33)
+{
+  return x33 || y33;
+}
+/* { dg-final { scan-tree-dump-times {return \(long int\) x33 != 0 \|\| \(long int\) y33 != 0;} 1 "original"  } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/intcap-valid.c b/gcc/testsuite/gcc.target/aarch64/morello/intcap-valid.c
index 8922019786d..fd73b81cae0 100644
--- a/gcc/testsuite/gcc.target/aarch64/morello/intcap-valid.c
+++ b/gcc/testsuite/gcc.target/aarch64/morello/intcap-valid.c
@@ -75,3 +75,10 @@ __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/tree.c b/gcc/tree.c
index 081727c9e4b..dcd85eedb41 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -7092,6 +7092,11 @@ type_cache_hasher::equal (type_hash *a, type_hash *b)
       return known_eq (TYPE_VECTOR_SUBPARTS (a->type),
 		       TYPE_VECTOR_SUBPARTS (b->type));
 
+    case INTCAP_TYPE:
+      gcc_assert (TYPE_CAP_PRECISION (a->type) == TYPE_CAP_PRECISION (b->type)
+		  && TYPE_UNSIGNED (a->type) == TYPE_UNSIGNED (b->type));
+      return 1;
+
     case ENUMERAL_TYPE:
       if (TYPE_VALUES (a->type) != TYPE_VALUES (b->type)
 	  && !(TYPE_VALUES (a->type)
@@ -7988,6 +7993,11 @@ build_intcap_type_for_mode (machine_mode mode, int unsignedp)
   set_min_and_max_values_for_integral_type
 	  (t, TYPE_CAP_PRECISION (t), unsignedp ? UNSIGNED : SIGNED);
 
+  /* Ensure the node we cache here is the same node you get when calling
+     type_hash_canon.  */
+  auto hash = type_hash_canon_hash (t);
+  t = type_hash_canon (hash, t);
+
   /* N.b. this is somewhat superfluous, since the time this function is called
      from `build_common_tree_nodes` will be the first time this function is
      called (since that is called from the language initialisation code), and


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

only message in thread, other threads:[~2022-05-20 10:42 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-20 10:42 [gcc(refs/vendors/ARM/heads/morello)] c: Fix up INTCAP_TYPE semantics 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).