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