A _BitInt value may rely on a conversion to become properly extended.
So a conversion to _BitInt is not trivially removable even if the
types of the result and the operand have the same precision and size.
This patches fixes gcc.dg/torture/bitint-64.c at -O2 on LoongArch,
which fails because extension of the result is dropped in a
compare-and-swap loop generated for incrementing an _Atomic _BitInt,
causing an ABI violation.
gcc/ChangeLog:
* match.pd: Preserve conversion to _BitInt before a VCE
if the _BitInt is extended.
---
gcc/match.pd | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/gcc/match.pd b/gcc/match.pd
index f4416d9172c..1df52155a05 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -5420,16 +5420,31 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(convert @0)))
/* Strip inner integral conversions that do not change precision or size, or
- zero-extend while keeping the same size (for bool-to-char). */
+ zero-extend while keeping the same size (for bool-to-char).
+ However, keep this conversion if the result is an extended _BitInt,
+ since it may rely on this conversion to extend properly. */
+
(simplify
(view_convert (convert@0 @1))
+ (with {
+ bool extended_bitint = false;
+ if (BITINT_TYPE_P (TREE_TYPE (@0)))
+ {
+ struct bitint_info info;
+ extended_bitint
+ = targetm.c.bitint_type_info (TYPE_PRECISION (TREE_TYPE (@0)),
+ &info);
+ extended_bitint = extended_bitint && info.extended;
+ }
+ }
(if ((INTEGRAL_TYPE_P (TREE_TYPE (@0)) || POINTER_TYPE_P (TREE_TYPE (@0)))
&& (INTEGRAL_TYPE_P (TREE_TYPE (@1)) || POINTER_TYPE_P (TREE_TYPE (@1)))
+ && !extended_bitint
&& TYPE_SIZE (TREE_TYPE (@0)) == TYPE_SIZE (TREE_TYPE (@1))
&& (TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1))
|| (TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (TREE_TYPE (@1))
&& TYPE_UNSIGNED (TREE_TYPE (@1)))))
- (view_convert @1)))
+ (view_convert @1))))
/* Simplify a view-converted empty or single-element constructor. */
(simplify
--
2.46.0