From: Eric Botcazou <ebotca...@adacore.com> This implements the new (sub)switch -gnatRh to display holes in the layout of record types, which are mostly present to fulfill alignment requirements.
gcc/ada/ChangeLog: * doc/gnat_ugn/building_executable_programs_with_gnat.rst (List of all switches): Add -gnatRh subswitch. (Debugging Control): Document -gnatRh subswitch. * opt.ads (List_Representation_Info_Holes): New boolean variable. * repinfo.adb: Add with clause for GNAT.Heap_Sort_G. (List_Common_Type_Info): Relax assertion. (List_Object_Info): Replace assertion with additional test. (List_Record_Layout): If -gnatRh is specified, make sure that the components are ordered by increasing offsets. Output a comment line giving the number of unused bits if there is a hole between consecutive components. Streamline the control flow of the loop. (List_Record_Info): Use the original record type giving the layout of components, if any, to display the layout of the record. * switch-c.adb (Scan_Front_End_Switches) <-gnatR>: Add support for -gnatRh subswitch. * usage.adb (Usage): Document -gnatRh subswitch. * gnat_ugn.texi: Regenerate. Tested on x86_64-pc-linux-gnu, committed on master. --- ...building_executable_programs_with_gnat.rst | 12 +- gcc/ada/gnat_ugn.texi | 12 +- gcc/ada/opt.ads | 25 +- gcc/ada/repinfo.adb | 299 ++++++++++++++---- gcc/ada/switch-c.adb | 21 +- gcc/ada/usage.adb | 2 +- 6 files changed, 280 insertions(+), 91 deletions(-) diff --git a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst index f5a9b021c4e..94e38efadfd 100644 --- a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst +++ b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst @@ -2112,7 +2112,7 @@ Alphabetical List of All Switches .. index:: -gnatR (gcc) -:switch:`-gnatR[0|1|2|3|4][e][j][m][s]` +:switch:`-gnatR[0|1|2|3|4][e][h][m][j][s]` Output representation information for declared types, objects and subprograms. Note that this switch is not allowed if a previous :switch:`-gnatD` switch has been given, since these two switches @@ -6090,7 +6090,7 @@ Debugging Control .. index:: -gnatR (gcc) -:switch:`-gnatR[0|1|2|3|4][e][j][m][s]` +:switch:`-gnatR[0|1|2|3|4][e][h][m][j][s]` This switch controls output from the compiler of a listing showing representation information for declared types, objects and subprograms. For :switch:`-gnatR0`, no information is output (equivalent to omitting @@ -6118,17 +6118,21 @@ Debugging Control extended representation information for record sub-components of records is included. + If the switch is followed by a ``h`` (e.g. :switch:`-gnatR3h`), then + the components of records are sorted by increasing offsets and holes + between consecutive components are flagged. + If the switch is followed by an ``m`` (e.g. :switch:`-gnatRm`), then subprogram conventions and parameter passing mechanisms for all the subprograms are included. - If the switch is followed by a ``j`` (e.g., :switch:`-gnatRj`), then + If the switch is followed by a ``j`` (e.g. :switch:`-gnatRj`), then the output is in the JSON data interchange format specified by the ECMA-404 standard. The semantic description of this JSON output is available in the specification of the Repinfo unit present in the compiler sources. - If the switch is followed by an ``s`` (e.g., :switch:`-gnatR3s`), then + If the switch is followed by an ``s`` (e.g. :switch:`-gnatR3s`), then the output is to a file with the name :file:`file.rep` where ``file`` is the name of the corresponding source file, except if ``j`` is also specified, in which case the file name is :file:`file.json`. diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi index 9d541db6e27..ad47780fdd4 100644 --- a/gcc/ada/gnat_ugn.texi +++ b/gcc/ada/gnat_ugn.texi @@ -9850,7 +9850,7 @@ Treat pragma Restrictions as Restriction_Warnings. @table @asis -@item @code{-gnatR[0|1|2|3|4][e][j][m][s]} +@item @code{-gnatR[0|1|2|3|4][e][h][m][j][s]} Output representation information for declared types, objects and subprograms. Note that this switch is not allowed if a previous @@ -15286,7 +15286,7 @@ restriction warnings rather than restrictions. @table @asis -@item @code{-gnatR[0|1|2|3|4][e][j][m][s]} +@item @code{-gnatR[0|1|2|3|4][e][h][m][j][s]} This switch controls output from the compiler of a listing showing representation information for declared types, objects and subprograms. @@ -15315,17 +15315,21 @@ If the switch is followed by an @code{e} (e.g. @code{-gnatR2e}), then extended representation information for record sub-components of records is included. +If the switch is followed by a @code{h} (e.g. @code{-gnatR3h}), then +the components of records are sorted by increasing offsets and holes +between consecutive components are flagged. + If the switch is followed by an @code{m} (e.g. @code{-gnatRm}), then subprogram conventions and parameter passing mechanisms for all the subprograms are included. -If the switch is followed by a @code{j} (e.g., @code{-gnatRj}), then +If the switch is followed by a @code{j} (e.g. @code{-gnatRj}), then the output is in the JSON data interchange format specified by the ECMA-404 standard. The semantic description of this JSON output is available in the specification of the Repinfo unit present in the compiler sources. -If the switch is followed by an @code{s} (e.g., @code{-gnatR3s}), then +If the switch is followed by an @code{s} (e.g. @code{-gnatR3s}), then the output is to a file with the name @code{file.rep} where @code{file} is the name of the corresponding source file, except if @code{j} is also specified, in which case the file name is @code{file.json}. diff --git a/gcc/ada/opt.ads b/gcc/ada/opt.ads index cbe470105fd..e595b084119 100644 --- a/gcc/ada/opt.ads +++ b/gcc/ada/opt.ads @@ -943,6 +943,21 @@ package Opt is -- WARNING: There is a matching C declaration of this variable in fe.h + List_Representation_Info_Extended : Boolean := False; + -- GNAT + -- Set true by -gnatRe switch. Causes extended information for record types + -- to be included in the representation output information. + + List_Representation_Info_Holes : Boolean := False; + -- GNAT + -- Set true by -gnatRh switch. Causes information for holes between record + -- components to be included in the representation output information. + + List_Representation_Info_Mechanisms : Boolean := False; + -- GNAT + -- Set true by -gnatRm switch. Causes information on mechanisms to be + -- included in the representation output information. + List_Representation_Info_To_File : Boolean := False; -- GNAT -- Set true by -gnatRs switch. Causes information from -gnatR[1-4]m to be @@ -955,16 +970,6 @@ package Opt is -- Set true by -gnatRj switch. Causes information from -gnatR[1-4]m to be -- output in the JSON data interchange format. - List_Representation_Info_Mechanisms : Boolean := False; - -- GNAT - -- Set true by -gnatRm switch. Causes information on mechanisms to be - -- included in the representation output information. - - List_Representation_Info_Extended : Boolean := False; - -- GNAT - -- Set true by -gnatRe switch. Causes extended information for record types - -- to be included in the representation output information. - List_Preprocessing_Symbols : Boolean := False; -- GNAT, GNATPREP -- Set to True if symbols for preprocessing a source are to be listed diff --git a/gcc/ada/repinfo.adb b/gcc/ada/repinfo.adb index a6dff7cc743..ddbb58e7e0b 100644 --- a/gcc/ada/repinfo.adb +++ b/gcc/ada/repinfo.adb @@ -30,6 +30,7 @@ with Debug; use Debug; with Einfo; use Einfo; with Einfo.Entities; use Einfo.Entities; with Einfo.Utils; use Einfo.Utils; +with GNAT.Heap_Sort_G; with Lib; use Lib; with Namet; use Namet; with Nlists; use Nlists; @@ -413,9 +414,9 @@ package body Repinfo is Write_Line (";"); end if; - -- Alignment is not always set for task, protected, and class-wide - -- types, or when doing semantic analysis only. Representation aspects - -- are not computed for types in a generic unit. + -- Alignment is not always set for concurrent types, class-wide types, + -- cloned subtypes, or when doing semantic analysis only. Representation + -- aspects are not computed for types declared in a generic unit. else -- Add unknown alignment entry in JSON format to ensure the format is @@ -426,11 +427,13 @@ package body Repinfo is Write_Unknown_Val; end if; - pragma Assert - (not Expander_Active or else - Is_Concurrent_Type (Ent) or else - Is_Class_Wide_Type (Ent) or else - Sem_Util.In_Generic_Scope (Ent)); + pragma Assert (not Expander_Active + or else Is_Concurrent_Type (Ent) + or else Is_Class_Wide_Type (Ent) + or else (Ekind (Ent) = E_Record_Subtype + and then Present (Cloned_Subtype (Ent)) + and then Has_Delayed_Freeze (Cloned_Subtype (Ent))) + or else Sem_Util.In_Generic_Scope (Ent)); end if; end List_Common_Type_Info; @@ -856,8 +859,7 @@ package body Repinfo is -- generic unit, or if the back end is not being run), don't try to -- print them. - pragma Assert (Known_Esize (Ent) = Known_Alignment (Ent)); - if not Known_Alignment (Ent) then + if not Known_Esize (Ent) or else not Known_Alignment (Ent) then return; end if; @@ -882,6 +884,7 @@ package body Repinfo is Write_Eol; Write_Line ("}"); + else Write_Str ("for "); List_Name (Ent); @@ -1223,11 +1226,135 @@ package body Repinfo is Starting_First_Bit : Uint := Uint_0; Prefix : String := "") is - Comp : Entity_Id; - First : Boolean := True; + function First_Comp_Or_Discr (Ent : Entity_Id) return Entity_Id; + -- Like First_Component_Or_Discriminant, but reorder the components + -- according to their bit offset if need be. + + ------------------------- + -- First_Comp_Or_Discr -- + ------------------------- + + function First_Comp_Or_Discr (Ent : Entity_Id) return Entity_Id is + + function Is_Placed_Before (C1, C2 : Entity_Id) return Boolean; + -- Return True if component C1 is placed before component C2 + + ---------------------- + -- Is_Placed_Before -- + ---------------------- + + function Is_Placed_Before (C1, C2 : Entity_Id) return Boolean is + begin + return Known_Static_Component_Bit_Offset (C1) + and then Known_Static_Component_Bit_Offset (C2) + and then + Component_Bit_Offset (C1) < Component_Bit_Offset (C2); + end Is_Placed_Before; + + -- Local variables + + Comp : Entity_Id; + N_Comp : Natural := 0; + Prev : Entity_Id; + Reorder : Boolean := False; + + -- Start of processing for First_Comp_Or_Discr + + begin + -- Reordering is needed only for -gnatRh + + if not List_Representation_Info_Holes then + return First_Component_Or_Discriminant (Ent); + end if; + + -- Count the number of components and whether reordering is needed + + Comp := First_Component_Or_Discriminant (Ent); + Prev := Comp; + + while Present (Comp) loop + N_Comp := N_Comp + 1; + + if not Reorder then + Reorder := Is_Placed_Before (Comp, Prev); + end if; + + Prev := Comp; + Next_Component_Or_Discriminant (Comp); + end loop; + + -- Reorder the components, if need be, by directly reshuffling the + -- list of entities between First_Entity and Last_Entity, which is + -- safe because we are invoked after compilation is finished. + + if Reorder then + declare + Comps : array (Natural range 0 .. N_Comp) of Entity_Id; + -- Support array for the heapsort + + function Lt (Op1, Op2 : Natural) return Boolean is + (Is_Placed_Before (Comps (Op1), Comps (Op2))); + -- Compare function for the heapsort + + procedure Move (From : Natural; To : Natural); + pragma Inline (Move); + -- Move procedure for the heapsort + + ---------- + -- Move -- + ---------- + + procedure Move (From : Natural; To : Natural) is + begin + Comps (To) := Comps (From); + end Move; + + package HS is new GNAT.Heap_Sort_G (Lt => Lt, Move => Move); + -- The heapsort for record components + + begin + -- Pack the components into the array + + N_Comp := 0; + Comp := First_Component_Or_Discriminant (Ent); + + while Present (Comp) loop + N_Comp := N_Comp + 1; + Comps (N_Comp) := Comp; + + Next_Component_Or_Discriminant (Comp); + end loop; + + -- Sort the array + + HS.Sort (N_Comp); + + -- Unpack the component into the list of entities + + Set_First_Entity (Ent, Comps (1)); + Set_Prev_Entity (Comps (1), Empty); + for J in 1 .. N_Comp - 1 loop + Set_Next_Entity (Comps (J), Comps (J + 1)); + Set_Prev_Entity (Comps (J + 1), Comps (J)); + end loop; + Set_Next_Entity (Comps (N_Comp), Empty); + Set_Last_Entity (Ent, Comps (N_Comp)); + end; + end if; + + return First_Component_Or_Discriminant (Ent); + end First_Comp_Or_Discr; + + -- Local variables + + Bit_Offset : Uint := Uint_0; + Comp : Entity_Id; + First : Boolean := True; + + -- Start of processing for List_Record_Layout begin - Comp := First_Component_Or_Discriminant (Ent); + Comp := First_Comp_Or_Discr (Ent); while Present (Comp) loop -- Skip a completely hidden discriminant or a discriminant in an @@ -1237,69 +1364,98 @@ package body Repinfo is and then (Is_Completely_Hidden (Comp) or else Is_Unchecked_Union (Ent)) then - goto Continue; - end if; + null; -- Skip _Parent component in extension (to avoid overlap) - if Chars (Comp) = Name_uParent then - goto Continue; - end if; + elsif Chars (Comp) = Name_uParent then + null; -- All other cases - declare - Ctyp : constant Entity_Id := Underlying_Type (Etype (Comp)); - Npos : constant Uint := Normalized_Position (Comp); - Fbit : constant Uint := Normalized_First_Bit (Comp); - Spos : Uint; - Sbit : Uint; + else + declare + C : constant Entity_Id := + (if Known_Normalized_Position (Comp) + then Comp + else Original_Record_Component (Comp)); + -- The Parent_Subtype in an extension is not back-annotated + -- but its layout is the same as that of the parent type. - begin - Get_Decoded_Name_String (Chars (Comp)); - Set_Casing (Unit_Casing); + Ctyp : constant Entity_Id := Underlying_Type (Etype (C)); - -- If extended information is requested, recurse fully into - -- record components, i.e. skip the outer level. + begin + Get_Decoded_Name_String (Chars (C)); + Set_Casing (Unit_Casing); - if List_Representation_Info_Extended - and then Is_Record_Type (Ctyp) - and then Known_Static_Normalized_Position (Comp) - and then Known_Static_Normalized_First_Bit (Comp) - then - Spos := Starting_Position + Npos; - Sbit := Starting_First_Bit + Fbit; + -- If extended information is requested, recurse fully into + -- record components, i.e. skip the outer level. - if Sbit >= SSU then - Spos := Spos + 1; - Sbit := Sbit - SSU; - end if; + if List_Representation_Info_Extended + and then Is_Record_Type (Ctyp) + and then Known_Static_Normalized_Position (C) + and then Known_Static_Normalized_First_Bit (C) + then + declare + Npos : constant Uint := Normalized_Position (C); + Fbit : constant Uint := Normalized_First_Bit (C); + Pref : constant String := + Prefix & Name_Buffer (1 .. Name_Len) & "."; - List_Record_Layout (Ctyp, - Spos, Sbit, Prefix & Name_Buffer (1 .. Name_Len) & "."); + Spos : Uint; + Sbit : Uint; - goto Continue; - end if; + begin + Spos := Starting_Position + Npos; + Sbit := Starting_First_Bit + Fbit; + + if Sbit >= SSU then + Spos := Spos + 1; + Sbit := Sbit - SSU; + end if; + + List_Record_Layout (Ctyp, Spos, Sbit, Pref); + end; - if List_Representation_Info_To_JSON then - if First then - Write_Eol; - First := False; else - Write_Line (","); + if List_Representation_Info_To_JSON then + if First then + Write_Eol; + First := False; + else + Write_Line (","); + end if; + end if; + + -- If information about holes is requested, update the + -- current bit offset and report any (static) gap. + + if List_Representation_Info_Holes + and then Known_Static_Component_Bit_Offset (C) + then + declare + Gap : constant Uint := + Component_Bit_Offset (C) - Bit_Offset; + begin + if Gap > Uint_0 then + Write_Str (" -- "); + UI_Write (Gap, Decimal); + Write_Line (" bits unused --"); + end if; + + if Known_Static_Esize (C) then + Bit_Offset := + Component_Bit_Offset (C) + Esize (C); + end if; + end; + end if; + + List_Component_Layout + (C, Starting_Position, Starting_First_Bit, Prefix); end if; - end if; + end; + end if; - -- The Parent_Subtype in an extension is not back-annotated - - List_Component_Layout ( - (if Known_Normalized_Position (Comp) - then Comp - else Original_Record_Component (Comp)), - Starting_Position, Starting_First_Bit, Prefix); - end; - - <<Continue>> Next_Component_Or_Discriminant (Comp); end loop; end List_Record_Layout; @@ -1610,6 +1766,17 @@ package body Repinfo is end loop; end List_Structural_Record_Layout; + -- Use the original record type giving the layout of components + -- to avoid repeated reordering when -gnatRh is specified. + + Rec : constant Entity_Id := + (if Ekind (Ent) = E_Record_Subtype + and then Present (Cloned_Subtype (Ent)) + then (if Is_Private_Type (Cloned_Subtype (Ent)) + then Full_View (Cloned_Subtype (Ent)) + else Cloned_Subtype (Ent)) + else Ent); + -- Start of processing for List_Record_Info begin @@ -1624,7 +1791,7 @@ package body Repinfo is -- First find out max line length and max starting position -- length, for the purpose of lining things up nicely. - Compute_Max_Length (Ent); + Compute_Max_Length (Rec); -- Then do actual output based on those values @@ -1636,21 +1803,21 @@ package body Repinfo is -- declared in the extended main source unit for the time being, -- because otherwise declarations might not be processed at all. - if Is_Base_Type (Ent) then + if Is_Base_Type (Rec) then begin - List_Structural_Record_Layout (Ent, Ent); + List_Structural_Record_Layout (Rec, Rec); exception when Incomplete_Layout | Not_In_Extended_Main => - List_Record_Layout (Ent); + List_Record_Layout (Rec); when others => raise Program_Error; end; else - List_Record_Layout (Ent); + List_Record_Layout (Rec); end if; Write_Eol; @@ -1660,7 +1827,7 @@ package body Repinfo is List_Name (Ent); Write_Line (" use record"); - List_Record_Layout (Ent); + List_Record_Layout (Rec); Write_Line ("end record;"); end if; diff --git a/gcc/ada/switch-c.adb b/gcc/ada/switch-c.adb index 1e54340d520..efad12c9c40 100644 --- a/gcc/ada/switch-c.adb +++ b/gcc/ada/switch-c.adb @@ -1220,17 +1220,20 @@ package body Switch.C is List_Representation_Info := Character'Pos (C) - Character'Pos ('0'); - when 's' => - List_Representation_Info_To_File := True; + when 'e' => + List_Representation_Info_Extended := True; - when 'j' => - List_Representation_Info_To_JSON := True; + when 'h' => + List_Representation_Info_Holes := True; when 'm' => List_Representation_Info_Mechanisms := True; - when 'e' => - List_Representation_Info_Extended := True; + when 'j' => + List_Representation_Info_To_JSON := True; + + when 's' => + List_Representation_Info_To_File := True; when others => Bad_Switch ("-gnatR" & Switch_Chars (Ptr .. Max)); @@ -1245,6 +1248,12 @@ package body Switch.C is Osint.Fail ("-gnatRe is incompatible with -gnatRj"); end if; + if List_Representation_Info_To_JSON + and then List_Representation_Info_Holes + then + Osint.Fail ("-gnatRh is incompatible with -gnatRj"); + end if; + -- -gnats (syntax check only) when 's' => diff --git a/gcc/ada/usage.adb b/gcc/ada/usage.adb index 3f6cd69b639..5b87bb54dca 100644 --- a/gcc/ada/usage.adb +++ b/gcc/ada/usage.adb @@ -402,7 +402,7 @@ begin Write_Switch_Char ("R?"); Write_Line - ("List rep info (?=0/1/2/3/4/e/m for none/types/all/sym/cg/ext/mech)"); + ("List rep info (?=1/2/3/4/e/h/m for types/all/sym/cg/ext/holes/mech)"); Write_Switch_Char ("R?j"); Write_Line ("List rep info in the JSON data interchange format"); Write_Switch_Char ("R?s"); -- 2.43.0