Hi,
fold_ctor_reference already punts on a CONSTRUCTOR whose type has reverse
storage order, but it can be invoked in a couple of places on a CONSTRUCTOR
with native storage order that has been wrapped in a VIEW_CONVERT_EXPR to a
type with reverse storage order; this would require a post adjustment that
does not currently exist, thus yield wrong code for this admittedly quite
pathological (but supported) case.
Technically, this is a regression in GCC 10.x and later but, being quite
pathological, at least in Ada, I don't think that we need to bother about it
on earlier branches than gcc-13.
Tested on x86-64/Linux, OK for mainline down to the gcc-13 branch?
2025-06-26 Eric Botcazou <ebotca...@adacore.com>
* gimple-fold.cc (fold_const_aggregate_ref_1) <COMPONENT_REF>:
Bail out immediately if the reference has reverse storage order.
* tree-ssa-sccvn.cc (fully_constant_vn_reference_p): Likewise.
2025-06-26 Eric Botcazou <ebotca...@adacore.com>
* gnat.dg/sso20.adb: New test.
--
Eric Botcazou
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 729080ad6e5..e9635d1005d 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -10117,19 +10117,21 @@ fold_const_aggregate_ref_1 (tree t, tree (*valueize) (tree))
base = get_ref_base_and_extent (t, &offset, &size, &max_size, &reverse);
ctor = get_base_constructor (base, &offset, valueize);
+ /* We cannot determine ctor. */
+ if (!ctor)
+ return NULL_TREE;
/* Empty constructor. Always fold to 0. */
if (ctor == error_mark_node)
return build_zero_cst (TREE_TYPE (t));
- /* We do not know precise address. */
+ /* We do not know precise access. */
if (!known_size_p (max_size) || maybe_ne (max_size, size))
return NULL_TREE;
- /* We cannot determine ctor. */
- if (!ctor)
- return NULL_TREE;
-
/* Out of bound array access. Value is undefined, but don't fold. */
if (maybe_lt (offset, 0))
return NULL_TREE;
+ /* Access with reverse storage order. */
+ if (reverse)
+ return NULL_TREE;
tem = fold_ctor_reference (TREE_TYPE (t), ctor, offset, size, base);
if (tem)
@@ -10149,7 +10151,6 @@ fold_const_aggregate_ref_1 (tree t, tree (*valueize) (tree))
&& offset.is_constant (&coffset)
&& (coffset % BITS_PER_UNIT != 0
|| csize % BITS_PER_UNIT != 0)
- && !reverse
&& BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN)
{
poly_int64 bitoffset;
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index f7f50c3de99..9cdbf3da772 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -1615,6 +1615,8 @@ fully_constant_vn_reference_p (vn_reference_t ref)
++i;
break;
}
+ if (operands[i].reverse)
+ return NULL_TREE;
if (known_eq (operands[i].off, -1))
return NULL_TREE;
off += operands[i].off;
-- { dg-do run }
-- { dg-options "-O" }
with Ada.Unchecked_Conversion;
with Interfaces; use Interfaces;
with System; use System;
procedure SSO20 is
type Bytes_Ref is array (1 .. 4) of Unsigned_8
with Convention => Ada_Pass_By_Reference;
type U32_BE is record
Value : Unsigned_32;
end record
with
Pack,
Bit_Order => High_Order_First,
Scalar_Storage_Order => High_Order_First;
function Conv is new Ada.Unchecked_Conversion (Bytes_Ref, U32_BE);
function Value (B : Bytes_Ref) return Unsigned_32 is (Conv (B).Value);
begin
if Value ((16#11#, 16#22#, 16#33#, 16#44#)) /= 16#11223344# then
raise Program_Error;
end if;
end;