Hi,
this is an interesting regression from GCC 4.5 present on all active branches
and triggered by recent SRA improvements. For the attached testcase, we have
an unchecked conversion of a 3-byte slice of an array of 4 bytes to a record
type containing a 3-byte bit-field; an unchecked conversion in this case
directly translates into a VIEW_CONVERT_EXPR. Then SRA scalarizes the bit-
field and turns the original VCE into a VCE of the 3-byte slice to the bit-
field type, which is a 32-bit integer with precision 24.
But the expansion of VCE isn't prepared for this and generates a full 32-bit
read, which thus reads 1 additional byte and doesn't mask it afterwards, thus
resulting in a wrong value for the scalarized bit-field.
Proposed fix attached, tested on x86-64/Linux, OK for the mainline?
2014-02-11 Eric Botcazou <ebotca...@adacore.com>
* expr.c (REDUCE_BIT_FIELD): Extend the scope of the macro.
(expand_expr_real_1) <case VIEW_CONVERT_EXPR>: Deal with bit-field
destination types.
2014-02-11 Eric Botcazou <ebotca...@adacore.com>
* gnat.dg/opt31.adb: New test.
--
Eric Botcazou
Index: expr.c
===================================================================
--- expr.c (revision 207685)
+++ expr.c (working copy)
@@ -9221,7 +9221,6 @@ expand_expr_real_2 (sepops ops, rtx targ
return temp;
return REDUCE_BIT_FIELD (temp);
}
-#undef REDUCE_BIT_FIELD
/* Return TRUE if expression STMT is suitable for replacement.
@@ -10444,15 +10443,21 @@ expand_expr_real_1 (tree exp, rtx target
op0 = target;
}
- /* At this point, OP0 is in the correct mode. If the output type is
+ /* If it's a MEM with a different mode and we need to reduce it to a
+ bit-field type, do an extraction. Otherwise, we can read all bits
+ of MODE but need to deal with the alignment. If the output type is
such that the operand is known to be aligned, indicate that it is.
- Otherwise, we need only be concerned about alignment for non-BLKmode
- results. */
+ Otherwise, we actually need only be concerned about alignment for
+ non-BLKmode results. */
if (MEM_P (op0))
{
enum insn_code icode;
- if (TYPE_ALIGN_OK (type))
+ if (reduce_bit_field && GET_MODE (op0) != mode)
+ return extract_bit_field (op0, TYPE_PRECISION (type), 0,
+ TYPE_UNSIGNED (type), NULL_RTX,
+ mode, mode);
+ else if (TYPE_ALIGN_OK (type))
{
/* ??? Copying the MEM without substantially changing it might
run afoul of the code handling volatile memory references in
@@ -10483,7 +10488,7 @@ expand_expr_real_1 (tree exp, rtx target
/* Nor can the insn generator. */
insn = GEN_FCN (icode) (reg, op0);
emit_insn (insn);
- return reg;
+ return REDUCE_BIT_FIELD (reg);
}
else if (STRICT_ALIGNMENT)
{
@@ -10513,7 +10518,7 @@ expand_expr_real_1 (tree exp, rtx target
op0 = adjust_address (op0, mode, 0);
}
- return op0;
+ return REDUCE_BIT_FIELD (op0);
case MODIFY_EXPR:
{
@@ -10613,6 +10618,7 @@ expand_expr_real_1 (tree exp, rtx target
return expand_expr_real_2 (&ops, target, tmode, modifier);
}
}
+#undef REDUCE_BIT_FIELD
/* Subroutine of above: reduce EXP to the precision of TYPE (in the
signedness of TYPE), possibly returning the result in TARGET. */
-- { dg-do run }
-- { dg-options "-O" }
with Interfaces; use Interfaces;
with Unchecked_Conversion;
procedure Opt31 is
type Unsigned_24 is new Unsigned_32 range 0 .. 2**24 - 1;
subtype Time_T is Unsigned_24 range 0 .. 24 * 60 * 60 * 128 - 1;
type Messages_T is array (Positive range <>) of Unsigned_8;
subtype T_3Bytes is Messages_T (1 .. 3);
type Rec1 is record
F : Time_T;
end record;
for Rec1 use record
F at 0 range 0 .. 23;
end record;
for Rec1'Size use 24;
type Rec2 is record
I1,I2,I3,I4 : Integer;
R1 : Rec1;
end record;
function Conv is new Unchecked_Conversion (T_3Bytes, Rec1);
procedure Decode (M : Messages_T) is
My_Rec2 : Rec2;
begin
My_Rec2.R1 := Conv (M (1 .. 3));
if not My_Rec2.R1.F'Valid then
raise Program_Error;
end if;
end;
Message : Messages_T (1 .. 4) := (16#18#, 16#0C#, 16#0C#, 16#18#);
begin
Decode (Message);
end;