[Ada] Simplify data structures for overloaded interpretations
authorPiotr Trojanek <trojanek@adacore.com>
Tue, 8 Dec 2020 21:34:29 +0000 (22:34 +0100)
committerPierre-Marie de Rodat <derodat@adacore.com>
Wed, 28 Apr 2021 09:38:15 +0000 (05:38 -0400)
gcc/ada/

* sem_type.ads (Write_Interp_Ref): Removed; no longer needed.
* sem_type.adb (Headers): Removed; now the hash table is
directly in the Interp_Map alone.
(Interp_Map): Now an instance of the GNAT.HTable.Simple_HTable.
(Last_Overloaded): New variable to emulate Interp_Map.Last.
(Add_One_Interp): Adapt to new data structure.
(Get_First_Interp): Likewise.
(Hash): Likewise.
(Init_Interp_Tables): Likewise.
(New_Interps): Likewise.
(Save_Interps): Likewise; handle O_N variable like in
Get_First_Interp.
(Write_Interp_Ref): Removed; no longer needed.

gcc/ada/sem_type.adb
gcc/ada/sem_type.ads

index 8f636be..8c12b08 100644 (file)
@@ -50,6 +50,8 @@ with Table;
 with Treepr;   use Treepr;
 with Uintp;    use Uintp;
 
+with GNAT.HTable; use GNAT.HTable;
+
 package body Sem_Type is
 
    ---------------------
@@ -60,21 +62,17 @@ package body Sem_Type is
    --  their interpretations. An overloaded node has an entry in Interp_Map,
    --  which in turn contains a pointer into the All_Interp array. The
    --  interpretations of a given node are contiguous in All_Interp. Each set
-   --  of interpretations is terminated with the marker No_Interp. In order to
-   --  speed up the retrieval of the interpretations of an overloaded node, the
-   --  Interp_Map table is accessed by means of a simple hashing scheme, and
-   --  the entries in Interp_Map are chained. The heads of clash lists are
-   --  stored in array Headers.
-
-   --              Headers        Interp_Map          All_Interp
-
-   --                 _            +-----+             +--------+
-   --                |_|           |_____|         --->|interp1 |
-   --                |_|---------->|node |         |   |interp2 |
-   --                |_|           |index|---------|   |nointerp|
-   --                |_|           |next |             |        |
-   --                              |-----|             |        |
-   --                              +-----+             +--------+
+   --  of interpretations is terminated with the marker No_Interp.
+
+   --     Interp_Map           All_Interp
+
+   --      +-----+             +--------+
+   --      |     |         --->|interp1 |
+   --      |_____|         |   |interp2 |
+   --      |index|---------|   |nointerp|
+   --      |-----|             |        |
+   --      |     |             |        |
+   --      +-----+             +--------+
 
    --  This scheme does not currently reclaim interpretations. In principle,
    --  after a unit is compiled, all overloadings have been resolved, and the
@@ -89,28 +87,26 @@ package body Sem_Type is
      Table_Increment      => Alloc.All_Interp_Increment,
      Table_Name           => "All_Interp");
 
-   type Interp_Ref is record
-      Node  : Node_Id;
-      Index : Interp_Index;
-      Next  : Int;
-   end record;
-
-   Header_Size : constant Int := 2 ** 12;
-   No_Entry    : constant Int := -1;
-   Headers     : array (0 .. Header_Size) of Int;
+   Header_Max : constant := 3079;
+   --  The number of hash buckets; an arbitrary prime number
 
-   package Interp_Map is new Table.Table (
-     Table_Component_Type => Interp_Ref,
-     Table_Index_Type     => Int,
-     Table_Low_Bound      => 0,
-     Table_Initial        => Alloc.Interp_Map_Initial,
-     Table_Increment      => Alloc.Interp_Map_Increment,
-     Table_Name           => "Interp_Map");
+   subtype Header_Num is Integer range 0 .. Header_Max - 1;
 
-   function Hash (N : Node_Id) return Int;
+   function Hash (N : Node_Id) return Header_Num;
    --  A trivial hashing function for nodes, used to insert an overloaded
    --  node into the Interp_Map table.
 
+   package Interp_Map is new Simple_HTable
+     (Header_Num => Header_Num,
+      Element    => Interp_Index,
+      No_Element => -1,
+      Key        => Node_Id,
+      Hash       => Hash,
+      Equal      => "=");
+
+   Last_Overloaded : Node_Id := Empty;
+   --  Overloaded node after initializing a new collection of intepretation
+
    -------------------------------------
    -- Handling of Overload Resolution --
    -------------------------------------
@@ -479,9 +475,9 @@ package body Sem_Type is
       --  node or the interpretation that is present is for a different
       --  node. In both cases add a new interpretation to the table.
 
-      elsif Interp_Map.Last < 0
+      elsif No (Last_Overloaded)
         or else
-          (Interp_Map.Table (Interp_Map.Last).Node /= N
+          (Last_Overloaded /= N
             and then not Is_Overloaded (N))
       then
          New_Interps (N);
@@ -2380,7 +2376,6 @@ package body Sem_Type is
       It : out Interp)
    is
       Int_Ind : Interp_Index;
-      Map_Ptr : Int;
       O_N     : Node_Id;
 
    begin
@@ -2398,21 +2393,16 @@ package body Sem_Type is
          O_N := N;
       end if;
 
-      Map_Ptr := Headers (Hash (O_N));
-      while Map_Ptr /= No_Entry loop
-         if Interp_Map.Table (Map_Ptr).Node = O_N then
-            Int_Ind := Interp_Map.Table (Map_Ptr).Index;
-            It := All_Interp.Table (Int_Ind);
-            I := Int_Ind;
-            return;
-         else
-            Map_Ptr := Interp_Map.Table (Map_Ptr).Next;
-         end if;
-      end loop;
+      Int_Ind := Interp_Map.Get (O_N);
 
       --  Procedure should never be called if the node has no interpretations
 
-      raise Program_Error;
+      if Int_Ind < 0 then
+         raise Program_Error;
+      end if;
+
+      I  := Int_Ind;
+      It := All_Interp.Table (Int_Ind);
    end Get_First_Interp;
 
    ---------------------
@@ -2545,12 +2535,9 @@ package body Sem_Type is
    -- Hash --
    ----------
 
-   function Hash (N : Node_Id) return Int is
+   function Hash (N : Node_Id) return Header_Num is
    begin
-      --  Nodes have a size that is power of two, so to select significant
-      --  bits only we remove the low-order bits.
-
-      return ((Int (N) / 2 ** 5) mod Header_Size);
+      return Header_Num (N mod Header_Max);
    end Hash;
 
    --------------
@@ -2575,8 +2562,7 @@ package body Sem_Type is
    procedure Init_Interp_Tables is
    begin
       All_Interp.Init;
-      Interp_Map.Init;
-      Headers := (others => No_Entry);
+      Interp_Map.Reset;
    end Init_Interp_Tables;
 
    -----------------------------------
@@ -3094,47 +3080,12 @@ package body Sem_Type is
    -----------------
 
    procedure New_Interps (N : Node_Id) is
-      Map_Ptr : Int;
-
    begin
       All_Interp.Append (No_Interp);
 
-      Map_Ptr := Headers (Hash (N));
-
-      if Map_Ptr = No_Entry then
-
-         --  Place new node at end of table
-
-         Interp_Map.Increment_Last;
-         Headers (Hash (N)) := Interp_Map.Last;
-
-      else
-         --   Place node at end of chain, or locate its previous entry
-
-         loop
-            if Interp_Map.Table (Map_Ptr).Node = N then
-
-               --  Node is already in the table, and is being rewritten.
-               --  Start a new interp section, retain hash link.
-
-               Interp_Map.Table (Map_Ptr).Node  := N;
-               Interp_Map.Table (Map_Ptr).Index := All_Interp.Last;
-               Set_Is_Overloaded (N, True);
-               return;
-
-            else
-               exit when Interp_Map.Table (Map_Ptr).Next = No_Entry;
-               Map_Ptr := Interp_Map.Table (Map_Ptr).Next;
-            end if;
-         end loop;
-
-         --  Chain the new node
-
-         Interp_Map.Increment_Last;
-         Interp_Map.Table (Map_Ptr).Next := Interp_Map.Last;
-      end if;
-
-      Interp_Map.Table (Interp_Map.Last) := (N, All_Interp.Last, No_Entry);
+      --  Add or rewrite the existing node
+      Last_Overloaded := N;
+      Interp_Map.Set (N, All_Interp.Last);
       Set_Is_Overloaded (N, True);
    end New_Interps;
 
@@ -3319,8 +3270,8 @@ package body Sem_Type is
    ------------------
 
    procedure Save_Interps (Old_N : Node_Id; New_N : Node_Id) is
-      Map_Ptr : Int;
-      O_N     : Node_Id := Old_N;
+      Old_Ind : Interp_Index;
+      O_N     : Node_Id;
 
    begin
       if Is_Overloaded (Old_N) then
@@ -3330,18 +3281,15 @@ package body Sem_Type is
            and then Is_Overloaded (Selector_Name (Old_N))
          then
             O_N := Selector_Name (Old_N);
+         else
+            O_N := Old_N;
          end if;
 
-         Map_Ptr := Headers (Hash (O_N));
-
-         while Interp_Map.Table (Map_Ptr).Node /= O_N loop
-            Map_Ptr := Interp_Map.Table (Map_Ptr).Next;
-            pragma Assert (Map_Ptr /= No_Entry);
-         end loop;
+         Old_Ind := Interp_Map.Get (O_N);
+         pragma Assert (Old_Ind >= 0);
 
          New_Interps (New_N);
-         Interp_Map.Table (Interp_Map.Last).Index :=
-           Interp_Map.Table (Map_Ptr).Index;
+         Interp_Map.Set (New_N, Old_Ind);
       end if;
    end Save_Interps;
 
@@ -3646,21 +3594,6 @@ package body Sem_Type is
       Print_Tree_Node (It.Abstract_Op);
    end Write_Interp;
 
-   ----------------------
-   -- Write_Interp_Ref --
-   ----------------------
-
-   procedure Write_Interp_Ref (Map_Ptr : Int) is
-   begin
-      Write_Str (" Node:  ");
-      Write_Int (Int (Interp_Map.Table (Map_Ptr).Node));
-      Write_Str (" Index: ");
-      Write_Int (Int (Interp_Map.Table (Map_Ptr).Index));
-      Write_Str (" Next:  ");
-      Write_Int (Interp_Map.Table (Map_Ptr).Next);
-      Write_Eol;
-   end Write_Interp_Ref;
-
    ---------------------
    -- Write_Overloads --
    ---------------------
index 3177bd3..a9c1ba2 100644 (file)
@@ -268,10 +268,6 @@ package Sem_Type is
    procedure Write_Interp (It : Interp);
    --  Debugging procedure to display an Interp
 
-   procedure Write_Interp_Ref (Map_Ptr : Int);
-   --  Debugging procedure to display entry in Interp_Map. Would not be needed
-   --  if it were possible to debug instantiations of Table.
-
    procedure Write_Overloads (N : Node_Id);
    --  Debugging procedure to output info on possibly overloaded entities for
    --  specified node.