public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] c, cp: Hande __intcap <op> T for higher-rank integral T
@ 2022-11-22 22:19 Alex Coplan
  0 siblings, 0 replies; only message in thread
From: Alex Coplan @ 2022-11-22 22:19 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:87492b28b1c35088d7452c3f6088f5985debd473

commit 87492b28b1c35088d7452c3f6088f5985debd473
Author: Alex Coplan <alex.coplan@arm.com>
Date:   Mon Nov 21 21:56:35 2022 +0000

    c, cp: Hande __intcap <op> T for higher-rank integral T
    
    This handles binary operations of the form __intcap <op> T where T is an
    integer type that out-ranks the non-capability type of the intcap type.
    
    Prior to this commit, for operands of types T1 and T2 of the above form,
    we would attempt to perform the address value arithmetic in the type:
    
      T' = common_type (noncapability_type (T1), noncapability_type (T2))
    
    but in CHERI C/C++, for an intcap type T1 and non-capability integer
    type T2, the address value arithmetic should be done in the type:
    
      T'' = noncapability_type (common_type (T1, T2))
    
    that is, since __intcap out-ranks all other integer types, both operands
    are logically first converted to a common intcap type, then the address
    value arithmetic is done in the non-capability type of that common type.
    
    When T2 is an integer of rank less than or equal to that of
    noncapability_type (T1), it happens that T' is the same type as T''. But
    when T2's rank exceeds that of noncapability_type (T1), these
    expressions give different types (leading our front-end code to hit an
    assertion failure). This commit fixes the implementation of binary
    operations with __intcap operands in the C and C++ FEs to give the
    correct semantics in this case, i.e. we perform the address value
    arithmetic in the type T''.

Diff:
---
 gcc/c-family/c-common.c                            |  26 ++++--
 gcc/c-family/c-common.h                            |   3 +-
 gcc/c/c-typeck.c                                   |  32 +++++--
 gcc/cp/typeck.c                                    |  33 +++++--
 .../g++.target/aarch64/morello/intcap-semantics.C  | 102 +++++++++++++++++++++
 .../gcc.target/aarch64/morello/intcap-semantics.c  | 102 +++++++++++++++++++++
 6 files changed, 270 insertions(+), 28 deletions(-)

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 7f48e050235..65e8a80286b 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -5178,25 +5178,26 @@ finish_label_address_expr (tree label, location_t loc)
    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.  */
+   is ambiguous.  LOC is the location that will be used for the warning.
+
+   *COMMON_IC_TYPE is set to the common intcap type that both operands
+   should be implicitly converted to, if any.  */
 tree
 binary_op_get_intcap_provenance (location_t loc,
 				 enum tree_code code,
 				 tree op0, tree op1,
-				 bool warn_p)
+				 bool warn_p,
+				 tree *common_ic_type)
 {
   tree type0 = TREE_TYPE (op0);
   tree type1 = TREE_TYPE (op1);
   bool ic0 = INTCAP_TYPE_P (type0);
   bool ic1 = INTCAP_TYPE_P (type1);
+  *common_ic_type = NULL_TREE;
 
   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)
@@ -5206,7 +5207,6 @@ 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:
@@ -5219,7 +5219,15 @@ binary_op_get_intcap_provenance (location_t loc,
   bool need_ic0 = ic0 && (ic1 || INTEGRAL_TYPE_P (type1));
   bool need_ic1 = ic1 && !shift && (ic0 || INTEGRAL_TYPE_P (type0));
 
-  if (!need_ic0 && !need_ic1)
+  if (!shift && (need_ic0 || need_ic1))
+    *common_ic_type = common_type (type0, type1);
+
+  /* Comparisons do not result in an intcap result type, but note
+     that both operands may need converting to a common intcap type
+     before we drop the capabilities.  */
+  if (TREE_CODE_CLASS (code) == tcc_comparison
+      || code == SPACESHIP_EXPR
+      || (!need_ic0 && !need_ic1))
     return NULL_TREE;
 
   static const char *cnp = "cheri_no_provenance";
@@ -5247,7 +5255,7 @@ binary_op_get_intcap_provenance (location_t loc,
      subexpression have cheri_no_provenance attributes).  */
   tree type;
   if (need_ic0 && need_ic1)
-    type = common_type (type0, type1);
+    type = *common_ic_type;
   else
     {
       type = need_ic0 ? type0 : type1;
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index ce07aabf49a..d995d214f9a 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1011,7 +1011,8 @@ 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);
+					     enum tree_code, tree, tree, bool,
+					     tree *);
 extern tree unary_op_get_intcap_provenance (tree);
 
 extern void warn_int_cap_conversion (location_t);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index cc832622165..1fcaa7dbebb 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -11958,8 +11958,10 @@ build_binary_op_1 (location_t location, enum tree_code code,
   orig_type0 = TREE_TYPE (op0);
   orig_type1 = TREE_TYPE (op1);
 
+  tree common_ic_type;
   tree intcap = binary_op_get_intcap_provenance (location, code, op0, op1,
-						 !op0_provenance_p);
+						 !op0_provenance_p,
+						 &common_ic_type);
 
   /* If we will derive an intcap from either the LHS or the RHS,
      wrap it with save_expr.  This will prevent us re-evaluating
@@ -11972,10 +11974,25 @@ build_binary_op_1 (location_t location, enum tree_code code,
   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)
-    op1 = drop_capability (op1);
+  if (common_ic_type)
+    {
+      if (intcap)
+	intcap = convert (common_ic_type, intcap);
+
+      /* Both sides are logically converted to a common intcap type,
+	 but we do the address value arithmetic on the non-capability
+	 type of that common intcap type.  */
+      tree av_type = noncapability_type (common_ic_type);
+      op0 = convert (av_type, op0);
+      op1 = convert (av_type, op1);
+    }
+  else
+    {
+      if (INTCAP_TYPE_P (TREE_TYPE (op0)))
+	op0 = drop_capability (op0);
+      if (INTCAP_TYPE_P (TREE_TYPE (op1)))
+	op1 = drop_capability (op1);
+    }
 
   type0 = nonic_type0 = TREE_TYPE (op0);
   type1 = nonic_type1 = TREE_TYPE (op1);
@@ -13059,10 +13076,7 @@ build_binary_op_1 (location_t location, enum tree_code code,
      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);
+      gcc_assert (TREE_TYPE (ret) == noncapability_type (TREE_TYPE (intcap)));
 
       /* We can't fold inside REPLACE_ADDRESS_VALUE calls, so ensure
 	 we've folded the operands.  */
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 0b398a18982..9434b5b0dbf 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -4581,8 +4581,10 @@ cp_build_binary_op (const op_location_t &location,
   STRIP_TYPE_NOPS (op0);
   STRIP_TYPE_NOPS (op1);
 
+  tree common_ic_type;
   tree intcap = binary_op_get_intcap_provenance (location, code, op0, op1,
-						 !op0_provenance_p);
+						 !op0_provenance_p,
+						 &common_ic_type);
 
   /* If we will derive an intcap from either the LHS or the RHS,
      wrap it with save_expr.  This will prevent us re-evaluating
@@ -4595,10 +4597,25 @@ cp_build_binary_op (const op_location_t &location,
   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)))
-    op1 = drop_capability (op1);
+  if (common_ic_type)
+    {
+      if (intcap)
+	intcap = convert (common_ic_type, intcap);
+
+      /* Both sides are logically converted to a common intcap type,
+	 but we do the address value arithmetic on the non-capability
+	 type of that common intcap type.  */
+      tree av_type = noncapability_type (common_ic_type);
+      op0 = convert (av_type, op0);
+      op1 = convert (av_type, op1);
+    }
+  else
+    {
+      if (INTCAP_TYPE_P (TREE_TYPE (op0)))
+	op0 = drop_capability (op0);
+      if (INTCAP_TYPE_P (TREE_TYPE (op1)))
+	op1 = drop_capability (op1);
+    }
 
   /* DTRT if one side is an overloaded function, but complain about it.  */
   if (type_unknown_p (op0))
@@ -5886,10 +5903,8 @@ cp_build_binary_op (const op_location_t &location,
      to work out where the provenance (if any) should come from.  */
   if (intcap)
     {
-      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);
+      gcc_assert (same_type_p (TREE_TYPE (result),
+			       noncapability_type (TREE_TYPE (intcap))));
       result = build_replace_address_value_loc (location,
 						intcap,
 						result);
diff --git a/gcc/testsuite/g++.target/aarch64/morello/intcap-semantics.C b/gcc/testsuite/g++.target/aarch64/morello/intcap-semantics.C
index 081d85fad69..7c4da66a73e 100644
--- a/gcc/testsuite/g++.target/aarch64/morello/intcap-semantics.C
+++ b/gcc/testsuite/g++.target/aarch64/morello/intcap-semantics.C
@@ -214,3 +214,105 @@ 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"  } } */
+
+__intcap f34 (__intcap x34, long long y34)
+{
+  return x34 + y34;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x34>, \(long int\) SAVE_EXPR <x34> \+ \(long int\) y34\)} 1 "original"  } } */
+
+unsigned __intcap f35 (unsigned __intcap x35, unsigned long long y35)
+{
+  return x35 + y35;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x35>, \(long unsigned int\) SAVE_EXPR <x35> \+ \(long unsigned int\) y35\)} 1 "original"  } } */
+
+unsigned __intcap f36 (__intcap x36, unsigned long long y36)
+{
+  return x36 + y36;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(\(unsigned __intcap\) SAVE_EXPR <x36>, \(long unsigned int\) SAVE_EXPR <x36> \+ \(long unsigned int\) y36\)} 1 "original"  } } */
+
+unsigned __intcap f37 (unsigned __intcap x37, long long y37)
+{
+  return x37 + y37;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x37>, \(long unsigned int\) SAVE_EXPR <x37> \+ \(long unsigned int\) y37\)} 1 "original"  } } */
+
+__intcap f38 (__intcap x38, __int128 y38)
+{
+  return x38 + y38;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x38>, \(long int\) SAVE_EXPR <x38> \+ \(long int\) y38\)} 1 "original"  } } */
+
+unsigned __intcap f39 (unsigned __intcap x39, unsigned __int128 y39)
+{
+  return x39 + y39;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x39>, \(long unsigned int\) SAVE_EXPR <x39> \+ \(long unsigned int\) y39\)} 1 "original"  } } */
+
+unsigned __intcap f40 (__intcap x40, unsigned __int128 y40)
+{
+  return x40 + y40;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(\(unsigned __intcap\) SAVE_EXPR <x40>, \(long unsigned int\) SAVE_EXPR <x40> \+ \(long unsigned int\) y40\)} 1 "original"  } } */
+
+unsigned __intcap f41 (unsigned __intcap x41, __int128 y41)
+{
+  return x41 + y41;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x41>, \(long unsigned int\) SAVE_EXPR <x41> \+ \(long unsigned int\) y41\)} 1 "original"  } } */
+
+bool f42 (__intcap x42, __intcap y42)
+{
+  return x42 == y42;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \(long int\) x42 == \(long int\) y42;} 1 "original" } } */
+
+bool f43 (__intcap x43, unsigned __intcap y43)
+{
+  return x43 == y43;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \(long unsigned int\) x43 == \(long unsigned int\) y43;} 1 "original" } } */
+
+bool f44 (unsigned __intcap x44, long y44)
+{
+  return x44 == y44;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \(long unsigned int\) x44 == \(long unsigned int\) y44;} 1 "original" } } */
+
+bool f45 (__intcap x45, long long y45)
+{
+  return x45 == y45;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \(long int\) x45 == \(long int\) y45;} 1 "original" } } */
+
+bool f46 (__intcap x46, unsigned long y46)
+{
+  return x46 == y46;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \(long unsigned int\) x46 == y46;} 1 "original" } } */
+
+bool f47 (__intcap x47, __int128 y47)
+{
+  return x47 == y47;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \(long int\) x47 == \(long int\) y47;} 1 "original" } } */
+
+bool f48 (__intcap x48, unsigned __int128 y48)
+{
+  return x48 == y48;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \(long unsigned int\) x48 == \(long unsigned int\) y48;} 1 "original" } } */
+
+__intcap f49 (__intcap x49, __int128 y49)
+{
+  return x49 << y49;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x49>, \(long int\) SAVE_EXPR <x49> << y49\)} 1 "original"  } } */
+
+__int128 f50 (__int128 x50, __intcap y50)
+{
+  return x50 << y50;
+}
+/* { dg-final { scan-tree-dump-times {<retval> = x50 << \(long int\) y50;} 1 "original" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/intcap-semantics.c b/gcc/testsuite/gcc.target/aarch64/morello/intcap-semantics.c
index 4104ae16179..394cd55ccce 100644
--- a/gcc/testsuite/gcc.target/aarch64/morello/intcap-semantics.c
+++ b/gcc/testsuite/gcc.target/aarch64/morello/intcap-semantics.c
@@ -214,3 +214,105 @@ 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"  } } */
+
+__intcap f34 (__intcap x34, long long y34)
+{
+  return x34 + y34;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x34>, \(long int\) SAVE_EXPR <x34> \+ \(long int\) y34\)} 1 "original"  } } */
+
+unsigned __intcap f35 (unsigned __intcap x35, unsigned long long y35)
+{
+  return x35 + y35;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x35>, \(long unsigned int\) SAVE_EXPR <x35> \+ \(long unsigned int\) y35\)} 1 "original"  } } */
+
+unsigned __intcap f36 (__intcap x36, unsigned long long y36)
+{
+  return x36 + y36;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(\(unsigned __intcap\) SAVE_EXPR <x36>, \(long unsigned int\) SAVE_EXPR <x36> \+ \(long unsigned int\) y36\)} 1 "original"  } } */
+
+unsigned __intcap f37 (unsigned __intcap x37, long long y37)
+{
+  return x37 + y37;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x37>, \(long unsigned int\) SAVE_EXPR <x37> \+ \(long unsigned int\) y37\)} 1 "original"  } } */
+
+__intcap f38 (__intcap x38, __int128 y38)
+{
+  return x38 + y38;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x38>, \(long int\) SAVE_EXPR <x38> \+ \(long int\) y38\)} 1 "original"  } } */
+
+unsigned __intcap f39 (unsigned __intcap x39, unsigned __int128 y39)
+{
+  return x39 + y39;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x39>, \(long unsigned int\) SAVE_EXPR <x39> \+ \(long unsigned int\) y39\)} 1 "original"  } } */
+
+unsigned __intcap f40 (__intcap x40, unsigned __int128 y40)
+{
+  return x40 + y40;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(\(unsigned __intcap\) SAVE_EXPR <x40>, \(long unsigned int\) SAVE_EXPR <x40> \+ \(long unsigned int\) y40\)} 1 "original"  } } */
+
+unsigned __intcap f41 (unsigned __intcap x41, __int128 y41)
+{
+  return x41 + y41;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x41>, \(long unsigned int\) SAVE_EXPR <x41> \+ \(long unsigned int\) y41\)} 1 "original"  } } */
+
+_Bool f42 (__intcap x42, __intcap y42)
+{
+  return x42 == y42;
+}
+/* { dg-final { scan-tree-dump-times {return \(long int\) x42 == \(long int\) y42;} 1 "original" } } */
+
+_Bool f43 (__intcap x43, unsigned __intcap y43)
+{
+  return x43 == y43;
+}
+/* { dg-final { scan-tree-dump-times {return \(long unsigned int\) x43 == \(long unsigned int\) y43;} 1 "original" } } */
+
+_Bool f44 (unsigned __intcap x44, long y44)
+{
+  return x44 == y44;
+}
+/* { dg-final { scan-tree-dump-times {return \(long unsigned int\) x44 == \(long unsigned int\) y44;} 1 "original" } } */
+
+_Bool f45 (__intcap x45, long long y45)
+{
+  return x45 == y45;
+}
+/* { dg-final { scan-tree-dump-times {return \(long int\) x45 == \(long int\) y45;} 1 "original" } } */
+
+_Bool f46 (__intcap x46, unsigned long y46)
+{
+  return x46 == y46;
+}
+/* { dg-final { scan-tree-dump-times {return \(long unsigned int\) x46 == y46;} 1 "original" } } */
+
+_Bool f47 (__intcap x47, __int128 y47)
+{
+  return x47 == y47;
+}
+/* { dg-final { scan-tree-dump-times {return \(long int\) x47 == \(long int\) y47;} 1 "original" } } */
+
+_Bool f48 (__intcap x48, unsigned __int128 y48)
+{
+  return x48 == y48;
+}
+/* { dg-final { scan-tree-dump-times {return \(long unsigned int\) x48 == \(long unsigned int\) y48;} 1 "original" } } */
+
+__intcap f49 (__intcap x49, __int128 y49)
+{
+  return x49 << y49;
+}
+/* { dg-final { scan-tree-dump-times {return \.REPLACE_ADDRESS_VALUE \(SAVE_EXPR <x49>, \(long int\) SAVE_EXPR <x49> << y49\)} 1 "original"  } } */
+
+__int128 f50 (__int128 x50, __intcap y50)
+{
+  return x50 << y50;
+}
+/* { dg-final { scan-tree-dump-times {return x50 << \(long int\) y50;} 1 "original" } } */

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

only message in thread, other threads:[~2022-11-22 22:19 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-22 22:19 [gcc(refs/vendors/ARM/heads/morello)] c, cp: Hande __intcap <op> T for higher-rank integral T 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).