public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] c: Fix double evaluation of intcap expressions
@ 2022-06-01 13:16 Alex Coplan
  0 siblings, 0 replies; only message in thread
From: Alex Coplan @ 2022-06-01 13:16 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:07cb14dd9017e450b3bf3459373405b494e1f05c

commit 07cb14dd9017e450b3bf3459373405b494e1f05c
Author: Alex Coplan <alex.coplan@arm.com>
Date:   Wed May 25 18:57:53 2022 +0100

    c: Fix double evaluation of intcap expressions
    
    For an intcap c and address offset cv, the C FE would generate:
    
    REPLACE_ADDRESS_VALUE (c, (long) c + cv)
    
    but this is problematic if c cannot safely be evaluated twice (e.g.
    for volatile variables, side-effecting function calls, etc.) as we end
    up getting any side effects twice. This can be seen with the
    intptr-eval.c test added with this patch, which was miscompiled on
    purecap Morello.
    
    To fix this, we need to use SAVE_EXPR on the intcap from which
    provenance is carried when building the REPLACE_ADDRESS_VALUE in the FE,
    so we get the tree:
    
    REPLACE_ADDRESS_VALUE (SAVE_EXPR <c>, (long) SAVE_EXPR <c> + cv)
    
    instead. This also means we need to make the provenance decision up
    front, so we know which operand needs SAVE_EXPRs. We add a new helper
    function, binary_op_get_intcap_provenance, to do this. We add this in
    c-family/c-common.c in anticipation that the same code might be useful
    in the C++ FE. Note that this change in how we make provenance decisions
    renders c_build_replace_address_value_1 and its wrapper functions
    redundant, so we remove these.
    
    As well as binary operations, similar fixes are needed for
    build_unary_op and its subroutine intcap_increment. In build_unary_op,
    for TRUTH_NOT_EXPR, we allow the intcap to be handled directly by the
    normal code (i.e. without dropping the capability): we don't want to
    re-derive an intcap here, and intcaps can be handled just fine by
    c_objc_common_truthvalue_conversion.
    
    Adding these SAVE_EXPRs can prevent some folding of
    REPLACE_ADDRESS_VALUE that we were getting before, thereby regressing
    code quality. The SAVE_EXPRs have TREE_SIDE_EFFECTs set, so some folds
    that were possible before are no longer possible. One such example is:
    
    (long) RAV (c, cv) --> cv.
    
    This transformation is only valid if c is free of side effects. In
    particular, if c is a SAVE_EXPR, we can't do this transformation.
    However, when this expression is gimplified, any SAVE_EXPRs will be
    lowered. At this point we should be able to apply the transformation.
    Hence, we add a match.pd rule for this that can be applied to the gimple
    after the SAVE_EXPRs are lowered. This fixes a code quality regression
    seen with nested binary ops such as:
    
    __intcap f(__intcap x, long y) { return x + y + y; }
    
    where (without the match.pd rule) we would end up generating two scvalue
    instructions. Further issues with the folding have been identified as
    part of this work, but are left to a follow-on patch to address.
    
    One further adjustment we make is to save_expr, where we teach it to
    push the save_expr inside REPLACE_ADDRESS_VALUE calls (down to the
    operands).  This allows the SAVE_EXPRs to be eliminated entirely in some
    cases (e.g.  when the operands are integer constants) and in general
    improves our chances of being able to fold the resulting expressions.
    
    gcc/c-family/ChangeLog:
    
            * c-common.c (binary_op_get_intcap_provenance): New.
            (unary_op_get_intcap_provenance): New.
            * c-common.h (binary_op_get_intcap_provenance): New.
            (unary_op_get_intcap_provenance): New.
    
    gcc/c/ChangeLog:
    
            * c-typeck.c (c_build_replace_address_value_1): Delete.
            (c_build_replace_address_value): Delete.
            (c_fold_build_replace_address_value): Delete.
            (intcap_increment): Avoid evaluating any intcap side-effects
            twice.
            (build_unary_op): Likewise.
            (build_binary_op_1): Likewise.
    
    gcc/ChangeLog:
    
            * match.pd (non-cap) RAV (c, cv) -> (non-cap) cv): New.
            * tree.c (save_expr): Push save_expr inside
            REPLACE_ADDRESS_VALUE operands.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/aarch64/morello/intcap-semantics.c: Add SAVE_EXPRs
            to some cases, following FE adjustments.
            * gcc.c-torture/execute/intptr-eval.c: New test.

Diff:
---
 gcc/c-family/c-common.c                            | 105 +++++++++++++++
 gcc/c-family/c-common.h                            |   4 +
 gcc/c/c-typeck.c                                   | 142 +++++++--------------
 gcc/match.pd                                       |  12 ++
 gcc/testsuite/gcc.c-torture/execute/intptr-eval.c  |  35 +++++
 .../gcc.target/aarch64/morello/intcap-semantics.c  |  32 ++---
 gcc/varasm.c                                       |  10 +-
 7 files changed, 226 insertions(+), 114 deletions(-)

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 2175d8cf69f..5390d5779aa 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -5183,6 +5183,111 @@ finish_label_address_expr (tree label, location_t loc)
 }
 \f
 
+/* Given operands OP0 and OP1 for a binary operation given by CODE,
+   return an operand of INTCAP_TYPE (if any) from which provenance
+   should be derived for the binary expression.
+
+   WARN_P should be set if we should warn when the provenance
+   is ambiguous.  LOC is the location that will be used for the warning.  */
+tree
+binary_op_get_intcap_provenance (location_t loc,
+				 enum tree_code code,
+				 tree op0, tree op1,
+				 bool warn_p)
+{
+  tree type0 = TREE_TYPE (op0);
+  tree type1 = TREE_TYPE (op1);
+  bool ic0 = INTCAP_TYPE_P (type0);
+  bool ic1 = INTCAP_TYPE_P (type1);
+
+  if (!ic0 && !ic1)
+    return NULL_TREE;
+
+  /* Comparisons don't return capabilities.  */
+  if (TREE_CODE_CLASS (code) == tcc_comparison)
+    return NULL_TREE;
+
+  bool shift = false;
+
+  switch (code)
+    {
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+      return NULL_TREE;
+    case RSHIFT_EXPR:
+    case LSHIFT_EXPR:
+      shift = true;
+      break;
+    default:
+      break;
+    }
+
+  bool need_ic0 = ic0 && (ic1 || INTEGRAL_TYPE_P (type1));
+  bool need_ic1 = ic1 && !shift && (ic0 || INTEGRAL_TYPE_P (type0));
+
+  if (!need_ic0 && !need_ic1)
+    return NULL_TREE;
+
+  static const char *cnp = "cheri_no_provenance";
+  bool prov0 = need_ic0 && !lookup_attribute (cnp, TYPE_ATTRIBUTES (type0));
+  bool prov1 = need_ic1 && !lookup_attribute (cnp, TYPE_ATTRIBUTES (type1));
+
+  if (prov0 && prov1 && warn_p)
+    {
+      warning_at (loc, OPT_Wcheri_provenance,
+	"binary expression on capability types %qT and %qT; "
+	"it is not clear which should be used as the source of provenance; "
+	"currently provenance is inherited from the left-hand side",
+	type0, type1);
+    }
+
+  if (prov0)
+    return op0;
+  if (prov1)
+    return op1;
+
+  /* MORELLO TODO: right now we don't propagate cheri_no_provenance
+     attributes, since this is what LLVM does, but it's actually
+     probably better to propagate these and avoid warning in cases where
+     the provenance is unambiguous (e.g. when all the operands of a
+     subexpression have cheri_no_provenance attributes).  */
+  tree type;
+  if (need_ic0 && need_ic1)
+    type = common_type (type0, type1);
+  else
+    {
+      type = need_ic0 ? type0 : type1;
+      tree attrs = remove_attribute (cnp, TYPE_ATTRIBUTES (type));
+      type = build_type_attribute_variant (type, attrs);
+    }
+
+  return build_int_cst (type, 0);
+}
+
+tree
+unary_op_get_intcap_provenance (tree c)
+{
+  /* MORELLO TODO: right now we don't propagate cheri_no_provenance
+     attributes, since this is what LLVM does, but it's actually
+     probably better to propagate these and avoid warning in cases where
+     the provenance is unambiguous (e.g. when all the operands of a
+     subexpression have cheri_no_provenance attributes).  */
+  tree type = TREE_TYPE (c);
+  tree attrs = TYPE_ATTRIBUTES (type);
+  static const char *cnp = "cheri_no_provenance";
+  if (lookup_attribute (cnp, attrs))
+    {
+      attrs = remove_attribute (cnp, attrs);
+      type = build_type_attribute_variant (type, attrs);
+      return build_int_cst (type, 0);
+    }
+
+  return c;
+}
+
 /* Given a boolean expression ARG, return a tree representing an increment
    or decrement (as indicated by CODE) of ARG.  The front end must check for
    invalid cases (e.g., decrement in C++).  */
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 88535e28feb..d7f74732e09 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1013,6 +1013,10 @@ extern tree common_type (tree, tree);
 
 extern tree decl_constant_value (tree);
 
+extern tree binary_op_get_intcap_provenance (location_t,
+					     enum tree_code, tree, tree, bool);
+extern tree unary_op_get_intcap_provenance (tree);
+
 /* Handle increment and decrement of boolean types.  */
 extern tree boolean_increment (enum tree_code, tree);
 
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 04a0528d6e8..f572b0607be 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -4353,52 +4353,28 @@ 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)
 {
-  tree t, cv;
+  tree t, cv, intcap, lval;
 
-  arg = stabilize_reference (arg);
+  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 = c_build_replace_address_value (loc, arg, t);
-  t = build2 (MODIFY_EXPR, TREE_TYPE (t), arg, 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);
@@ -4440,6 +4416,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
   if (!ADDR_EXPR_CODE_P (code))
     arg = require_complete_type (location, arg);
 
+  tree intcap = NULL_TREE;
   if (TREE_CODE (TREE_TYPE (arg)) == INTCAP_TYPE)
     {
       switch (code)
@@ -4450,8 +4427,12 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
 	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);
 	}
     }
@@ -4584,7 +4565,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
     case TRUTH_NOT_EXPR:
       if (typecode != INTEGER_TYPE && typecode != FIXED_POINT_TYPE
 	  && typecode != REAL_TYPE && typecode != POINTER_TYPE
-	  && typecode != COMPLEX_TYPE)
+	  && typecode != COMPLEX_TYPE && typecode != INTCAP_TYPE)
 	{
 	  error_at (location,
 		    "wrong type argument to unary exclamation mark");
@@ -4959,9 +4940,8 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
   else
     ret = build1 (code, argtype, arg);
 
-  if (TREE_CODE (TREE_TYPE (xarg)) == INTCAP_TYPE
-      && !capability_type_p (TREE_TYPE (ret)))
-    ret = c_fold_build_replace_address_value (location, xarg, ret);
+  if (intcap)
+    ret = fold_build_replace_address_value_loc (location, intcap, ret);
 
  return_build_unary_op:
   gcc_assert (ret != error_mark_node);
@@ -12022,6 +12002,20 @@ build_binary_op_1 (location_t location, enum tree_code code,
   orig_type0 = TREE_TYPE (op0);
   orig_type1 = TREE_TYPE (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 (TREE_CODE (orig_type0) == INTCAP_TYPE)
     op0 = drop_capability (op0);
   if (TREE_CODE (orig_type1) == INTCAP_TYPE)
@@ -13106,65 +13100,19 @@ build_binary_op_1 (location_t location, enum tree_code code,
 
 
   /* 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 (ret))
-      && TREE_CODE_CLASS (code) != tcc_comparison
-      && !boolean_op)
-    {
-      bool ic0 = TREE_CODE (orig_type0) == INTCAP_TYPE;
-      bool ic1 = TREE_CODE (orig_type1) == INTCAP_TYPE;
-
-      /* 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;
-
-      static const char * const cnp = "cheri_no_provenance";
-      bool prov0 = need_ic0
-		   && !lookup_attribute (cnp,
-					 TYPE_ATTRIBUTES (orig_type0));
-      bool prov1 = need_ic1
-		   && !lookup_attribute (cnp,
-					 TYPE_ATTRIBUTES (orig_type1));
-
-      tree intcap = NULL;
-      if (prov0)
-	intcap = orig_op0;
-      else if (prov1)
-	intcap = orig_op1;
-      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)
-	{
-	  tree ic_type = c_common_type (TREE_TYPE (intcap), TREE_TYPE (ret));
-	  gcc_assert (TREE_TYPE (ret) == noncapability_type (ic_type));
-	  intcap = convert (ic_type, intcap);
-
-	  /* We can't fold inside REPLACE_ADDRESS_VALUE calls, so ensure
-	     we've folded the operands.  */
-	  ret = c_fully_fold (ret, false, NULL);
-	  intcap = c_fully_fold (intcap, false, NULL);
-	  ret = fold_build_replace_address_value_loc (location, intcap, ret);
-	}
-
-	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; "
-	    "currently provenance is inherited from the left-hand side",
-	    orig_type0, orig_type1);
+     to derive the final intcap expression.  */
+  if (intcap)
+    {
+      gcc_assert (!capability_type_p (TREE_TYPE (ret)));
+      tree ic_type = c_common_type (TREE_TYPE (intcap), TREE_TYPE (ret));
+      gcc_assert (TREE_TYPE (ret) == noncapability_type (ic_type));
+      intcap = convert (ic_type, intcap);
+
+      /* We can't fold inside REPLACE_ADDRESS_VALUE calls, so ensure
+	 we've folded the operands.  */
+      ret = c_fully_fold (ret, false, NULL);
+      intcap = c_fully_fold (intcap, false, NULL);
+      ret = fold_build_replace_address_value_loc (location, intcap, ret);
     }
 
  return_build_binary_op:
diff --git a/gcc/match.pd b/gcc/match.pd
index 200afaa0ef3..34eb9d2a92e 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -6571,3 +6571,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    to the number of trailing zeroes.  */
 (match (ctz_table_index @1 @2 @3)
   (rshift (mult (bit_and:c (negate @1) @1) INTEGER_CST@2) INTEGER_CST@3))
+
+#if GIMPLE
+
+/* (non-cap) RAV (c, cv) -> (non-cap) cv.  */
+(simplify
+  (convert
+    (IFN_REPLACE_ADDRESS_VALUE @0 @1))
+  (if (INTEGRAL_TYPE_P (type)
+       && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@1)))
+   (convert @1)))
+
+#endif
diff --git a/gcc/testsuite/gcc.c-torture/execute/intptr-eval.c b/gcc/testsuite/gcc.c-torture/execute/intptr-eval.c
new file mode 100644
index 00000000000..dd7a13ced83
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/intptr-eval.c
@@ -0,0 +1,35 @@
+/* This was being miscompiled on capability targets since we were
+   incorrectly evaluating intcap operands twice: once to get the
+   capability, and again to get the capability value.  */
+
+int i;
+__INTPTR_TYPE__ f() { i++; return 1; }
+__INTPTR_TYPE__ bin() { return f() + 1; }
+__INTPTR_TYPE__ un() { return -f(); }
+
+__INTPTR_TYPE__ x;
+__INTPTR_TYPE__ *get_ptr() { i++; return &x; }
+__INTPTR_TYPE__ preinc() { return ++get_ptr()[0]; }
+__INTPTR_TYPE__ postinc() { return get_ptr()[0]++; }
+
+int main(void)
+{
+  if (bin() != 2)
+    __builtin_abort ();
+  if (i != 1)
+    __builtin_abort ();
+  if (un() != -1)
+    __builtin_abort ();
+  if (i != 2)
+    __builtin_abort ();
+  if (preinc() != 1)
+    __builtin_abort ();
+  if (i != 3)
+    __builtin_abort ();
+  if (postinc() != 1)
+    __builtin_abort ();
+  if (i != 4)
+    __builtin_abort ();
+  if (x != 2)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/intcap-semantics.c b/gcc/testsuite/gcc.target/aarch64/morello/intcap-semantics.c
index 6f83dd91383..4104ae16179 100644
--- a/gcc/testsuite/gcc.target/aarch64/morello/intcap-semantics.c
+++ b/gcc/testsuite/gcc.target/aarch64/morello/intcap-semantics.c
@@ -7,43 +7,43 @@ __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"  } } */
+/* { dg-final { scan-tree-dump-times {return \.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 {return \.REPLACE_ADDRESS_VALUE \(x2, \(long int\) x2 \+ \(long int\) y2\)} 1 "original"  } } */
+/* { dg-final { scan-tree-dump-times {return \.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 {return \.REPLACE_ADDRESS_VALUE \(x3, \(long int\) x3 \+ \(long int\) y3\)} 1 "original"  } } */
+/* { dg-final { scan-tree-dump-times {return \.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 {return \.REPLACE_ADDRESS_VALUE \(x4, \(long int\) x4 \+ \(long int\) y4\)} 1 "original"  } } */
+/* { dg-final { scan-tree-dump-times {return \.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 {return \.REPLACE_ADDRESS_VALUE \(\(unsigned __intcap\) x5, \(long unsigned int\) x5 \+ y5\)} 1 "original"  } } */
+/* { dg-final { scan-tree-dump-times {return \.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 {return \.REPLACE_ADDRESS_VALUE \(x6, \(long unsigned int\) x6 \+ y6\)} 1 "original"  } } */
+/* { dg-final { scan-tree-dump-times {return \.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 {return \.REPLACE_ADDRESS_VALUE \(x7, \(long unsigned int\) x7 \+ \(long unsigned int\) y7\)} 1 "original"  } } */
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x7>, \(long unsigned int\) SAVE_EXPR <x7> \+ \(long unsigned int\) y7\)} 1 "original"  } } */
 
 _Bool f8(__intcap x8, __intcap y8)
 {
@@ -85,13 +85,13 @@ __intcap f14(__intcap x14)
 {
   return -x14;
 }
-/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(x14, * -\(long int\) x14\);} 1 "original"  } } */
+/* { dg-final { scan-tree-dump-times {return \.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 {return \.REPLACE_ADDRESS_VALUE \(x15, * ~\(long int\) x15\);} 1 "original"  } } */
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x15>, ~\(long int\) SAVE_EXPR <x15>\);} 1 "original"  } } */
 
 _Bool f16(__intcap x16)
 {
@@ -110,14 +110,14 @@ __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"  } } */
+/* { dg-final { scan-tree-dump-times {return \.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 {return \.REPLACE_ADDRESS_VALUE \(x19, \(long int\) x19 \+ \(long int\) y19\)} 1 "original"  } } */
+/* { dg-final { scan-tree-dump-times {return \.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)))
@@ -168,13 +168,13 @@ __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"  } } */
+/* { dg-final { scan-tree-dump-times {return 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(void) {
     return ++x27;
 }
-/* { dg-final { scan-tree-dump-times {return x27 = \.REPLACE_ADDRESS_VALUE \(x27, \(long int\) x27 \+ 1\);} 1 "original"  } } */
+/* { dg-final { scan-tree-dump-times {return x27 = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x27>, \(long int\) SAVE_EXPR <x27> \+ 1\);} 1 "original"  } } */
 
 __intcap x28 __attribute__((cheri_no_provenance));
 __intcap f28(void) {
@@ -194,20 +194,20 @@ __intcap f30(__intcap x30,
 {
   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"  } } */
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x30>, \(long int\) SAVE_EXPR <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"  } } */
+/* { 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 {return \.REPLACE_ADDRESS_VALUE \(x32, \(long int\) x32 << \(long int\) y32\)} 1 "original"  } } */
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x32>, \(long int\) SAVE_EXPR <x32> << \(long int\) y32\)} 1 "original"  } } */
 
 int f33 (__intcap x33, __intcap y33)
 {
diff --git a/gcc/varasm.c b/gcc/varasm.c
index d680f01690d..a35048676d2 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -4613,10 +4613,16 @@ narrowing_initializer_constant_valid_p (tree value, tree endtype, tree *cache)
    cleared metadata).
 
    That should ensure we don't start handling capabilities with non-zero
-   metadata without knowing why & where it comes from.  */
+   metadata without knowing why & where it comes from.
+
+   Returns NULL_TREE if T cannot be a valid base capability for an
+   initializer constant.  */
 inline const_tree
 tree_innermost_capability (const_tree t)
 {
+  if (TREE_SIDE_EFFECTS (t))
+    return NULL_TREE;
+
   switch (TREE_CODE (t))
     {
     case INTEGER_CST:
@@ -4666,6 +4672,8 @@ initializer_constant_valid_p_1 (tree value, tree endtype, tree *cache)
 	  break;
 
 	const_tree base_cap = tree_innermost_capability (ptr);
+	if (!base_cap)
+	  break;
 
 	tree ptr_ret = initializer_constant_valid_p_1 (ptr, endtype, cache);
 	tree addrval_ret = initializer_constant_valid_p_1


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

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

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-01 13:16 [gcc(refs/vendors/ARM/heads/morello)] c: Fix double evaluation of intcap expressions 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).