For targets that have extended bitints, we need to ensure these
are extended before writing to the memory, including via atomic
exchange.

gcc/c-family/ChangeLog:

        * c-common.cc (resolve_overloaded_atomic_exchange): Extend
        _BitInts before atomic exchange if needed.
        (resolve_overloaded_atomic_compare_exchange): Same.
---
 gcc/c-family/c-common.cc | 63 +++++++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 8 deletions(-)

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index f71cb2652d5..962e9d2a639 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -8059,11 +8059,35 @@ resolve_overloaded_atomic_exchange (location_t loc, 
tree function,
   /* Convert new value to required type, and dereference it.
      If *p1 type can have padding or may involve floating point which
      could e.g. be promoted to wider precision and demoted afterwards,
-     state of padding bits might not be preserved.  */
+     state of padding bits might not be preserved.
+
+     However, as a special case, we still want to preserve the padding
+     bits of _BitInt values if the ABI requires them to be extended in
+     memory.  */
+
   build_indirect_ref (loc, p1, RO_UNARY_STAR);
-  p1 = build2_loc (loc, MEM_REF, I_type,
-                  build1 (VIEW_CONVERT_EXPR, I_type_ptr, p1),
-                  build_zero_cst (TREE_TYPE (p1)));
+
+  tree p1type = TREE_TYPE (p1);
+  bool bitint_extended_p = false;
+  if (TREE_CODE (TREE_TYPE (p1type)) == BITINT_TYPE)
+    {
+      struct bitint_info info;
+      unsigned prec = TYPE_PRECISION (TREE_TYPE (p1type));
+      targetm.c.bitint_type_info (prec, &info);
+      bitint_extended_p = info.extended;
+    }
+
+  if (bitint_extended_p)
+    p1 = fold_convert_loc (loc, I_type,
+                          build2_loc (loc, MEM_REF, TREE_TYPE (p1type),
+                                      p1, build_zero_cst (p1type)));
+  /* Otherwise, the padding bits might not be preserved, as stated above.  */
+  else
+    p1 = build2_loc (loc, MEM_REF, I_type,
+                    build1 (VIEW_CONVERT_EXPR, I_type_ptr, p1),
+                    build_zero_cst (p1type));
+
+
   (*params)[1] = p1;
 
   /* Move memory model to the 3rd position, and end param list.  */
@@ -8143,11 +8167,34 @@ resolve_overloaded_atomic_compare_exchange (location_t 
loc, tree function,
   /* Convert desired value to required type, and dereference it.
      If *p2 type can have padding or may involve floating point which
      could e.g. be promoted to wider precision and demoted afterwards,
-     state of padding bits might not be preserved.  */
+     state of padding bits might not be preserved.
+
+     However, as a special case, we still want to preserve the padding
+     bits of _BitInt values if the ABI requires them to be extended in
+     memory.  */
+
   build_indirect_ref (loc, p2, RO_UNARY_STAR);
-  p2 = build2_loc (loc, MEM_REF, I_type,
-                  build1 (VIEW_CONVERT_EXPR, I_type_ptr, p2),
-                  build_zero_cst (TREE_TYPE (p2)));
+
+  tree p2type = TREE_TYPE (p2);
+  bool bitint_extended_p = false;
+  if (TREE_CODE (TREE_TYPE (p2type)) == BITINT_TYPE)
+    {
+      struct bitint_info info;
+      unsigned prec = TYPE_PRECISION (TREE_TYPE (p2type));
+      targetm.c.bitint_type_info (prec, &info);
+      bitint_extended_p = info.extended;
+    }
+
+  if (bitint_extended_p)
+    p2 = fold_convert_loc (loc, I_type,
+                          build2_loc (loc, MEM_REF, TREE_TYPE (p2type),
+                                      p2, build_zero_cst (p2type)));
+  /* Otherwise, the padding bits might not be preserved, as stated above.  */
+  else
+    p2 = build2_loc (loc, MEM_REF, I_type,
+                    build1 (VIEW_CONVERT_EXPR, I_type_ptr, p2),
+                    build_zero_cst (p2type));
+
   (*params)[2] = p2;
 
   /* The rest of the parameters are fine. NULL means no special return value
-- 
2.46.0

Reply via email to