This patch improves on the code generated for an assignment to a component of a bit-packed array, when lhs and rhs have a different representation.
Executing the following : gcc -c -gnatG p1.adb | grep -c '\$system__pack_40' must yield: 1 --- package Conf is type UINT32_T is mod 2**32; for UINT32_T'SIZE use 32; type UINT4_T is mod 2**4; for UINT4_T'SIZE use 4; -- record type type REC_T is record SIZE : UINT32_T; V1, V2 : Uint4_T; end record; -- packed record type type REC_pack_T is new REC_T; for REC_pack_T use record SIZE at 0 range 0 .. 31; -- 32 bits V1 at 0 range 32 .. 35; -- 4 bits V2 at 0 range 36 .. 39; -- 4 bits end record; for REC_pack_T'Size use 40; -- packed arrays of each record type subtype ARRAY_INDEX_T is Integer range 1 .. 10; type PARR_R_T is array (ARRAY_INDEX_T) of REC_T; pragma Pack (PARR_R_T); type PARR_PR_T is array(ARRAY_INDEX_T) of REC_PACK_T; pragma Pack (PARR_PR_T); -- data Csz : constant Uint32_T := 0; Cv1 : constant Uint4_T := 0; Cv2 : constant Uint4_T := 3; A_R : PARR_R_T := (others => (SIZE => Csz, V1 => Cv1, V2 => Cv2)); -- procedure Assert (Cond : Boolean); PR : REC_PACK_T; A_PR : PARR_PR_T; INDEX : constant := 8; end; --- with Conf; use Conf; procedure P1 is begin PR := REC_PACK_T(A_R (INDEX)); A_PR (INDEX) := PR; end; Tested on x86_64-pc-linux-gnu, committed on trunk 2011-08-29 Ed Schonberg <schonb...@adacore.com> * exp_ch5.adb (Expand_N_Assignment_Statement): if the left-hand side is an indexed component of a packed array whose element type is a record with a representation clause different from that of the right-hand side, generate a temporary to minimuze the number of bit-field operations generated.
Index: exp_ch5.adb =================================================================== --- exp_ch5.adb (revision 178177) +++ exp_ch5.adb (working copy) @@ -1890,11 +1890,42 @@ if Nkind (Lhs) = N_Indexed_Component and then Is_Bit_Packed_Array (Etype (Prefix (Lhs))) - and then not Crep then - Expand_Bit_Packed_Element_Set (N); - return; + if not Crep then + Expand_Bit_Packed_Element_Set (N); + return; + else + -- Generate the following, to force component-by-component + -- assignments in an efficient way. Otherwise each component + -- will require a temporary and two bit-field manipulations. + + -- T1 : Elmt_Type; + -- T1 := RhS; + -- Lhs := T1; + + declare + Tnn : constant Entity_Id := Make_Temporary (Loc, 'T'); + Stats : List_Id; + + begin + Stats := New_List ( + Make_Object_Declaration (Loc, + Defining_Identifier => Tnn, + Object_Definition => New_Occurrence_Of (Etype (Lhs), Loc)), + Make_Assignment_Statement (Loc, + Name => New_Occurrence_Of (Tnn, Loc), + Expression => Relocate_Node (Rhs)), + Make_Assignment_Statement (Loc, + Name => Relocate_Node (Lhs), + Expression => New_Occurrence_Of (Tnn, Loc))); + + Insert_Actions (N, Stats); + Rewrite (N, Make_Null_Statement (Loc)); + Analyze (N); + end; + end if; + -- Build-in-place function call case. Note that we're not yet doing -- build-in-place for user-written assignment statements (the assignment -- here came from an aggregate.)