From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7810) id C354538515C5; Fri, 20 May 2022 10:42:40 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C354538515C5 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Alex Coplan To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/vendors/ARM/heads/morello)] c: Fix up INTCAP_TYPE semantics X-Act-Checkin: gcc X-Git-Author: Alex Coplan X-Git-Refname: refs/vendors/ARM/heads/morello X-Git-Oldrev: 69ad45741ef85f20c6b2a6a1f73ab899c4c84082 X-Git-Newrev: d7f8b9c884e6543aefe40c13fdd19f4caa997026 Message-Id: <20220520104240.C354538515C5@sourceware.org> Date: Fri, 20 May 2022 10:42:40 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 20 May 2022 10:42:40 -0000 https://gcc.gnu.org/g:d7f8b9c884e6543aefe40c13fdd19f4caa997026 commit d7f8b9c884e6543aefe40c13fdd19f4caa997026 Author: Alex Coplan 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); /* 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 = \.REPLACE_ADDRESS_VALUE \(x26, \(long int\) x26 \+ 1\);, SAVE_EXPR ;;} 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 = \.REPLACE_ADDRESS_VALUE \(0, \(long int\) x29 \+ 1\);, SAVE_EXPR ;;} 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