This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Fix wrong code with VCE to bit-field type at -O


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  <ebotcazou@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  <ebotcazou@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;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]