diff options
author | Tristan Gingold <tgingold@free.fr> | 2016-07-09 08:41:41 +0200 |
---|---|---|
committer | Tristan Gingold <tgingold@free.fr> | 2016-07-09 19:51:30 +0200 |
commit | 9b3a3f19e60074bea408a057fd736973620a7267 (patch) | |
tree | d91cf2dfc0b8d3950f79f2fdffcd6ddd3f956855 /src/ortho/oread/ortho_front.adb | |
parent | 8365da6519d46d841aaef894aab17c4f27312703 (diff) | |
download | ghdl-9b3a3f19e60074bea408a057fd736973620a7267.tar.gz ghdl-9b3a3f19e60074bea408a057fd736973620a7267.tar.bz2 ghdl-9b3a3f19e60074bea408a057fd736973620a7267.zip |
oread: optimize field search for large record/unions (use a hash map).
Diffstat (limited to 'src/ortho/oread/ortho_front.adb')
-rw-r--r-- | src/ortho/oread/ortho_front.adb | 167 |
1 files changed, 120 insertions, 47 deletions
diff --git a/src/ortho/oread/ortho_front.adb b/src/ortho/oread/ortho_front.adb index 0ef96914e..bcdd4db16 100644 --- a/src/ortho/oread/ortho_front.adb +++ b/src/ortho/oread/ortho_front.adb @@ -226,8 +226,13 @@ package body Ortho_Front is -- The symbol table. type Syment_Acc_Array is array (Hash_Type range <>) of Syment_Acc; + type Syment_Acc_Map (Max : Hash_Type) is record + Map : Syment_Acc_Array (0 .. Max); + end record; + -- type Syment_Acc_Map_Acc is access Syment_Acc_Map; + Hash_Max : constant Hash_Type := 511; - Symtable : Syment_Acc_Array (0 .. Hash_Max - 1) := (others => null); + Symtable : Syment_Acc_Map (Hash_Max - 1); type Node_Kind is (Decl_Keyword, Decl_Type, Decl_Param, Node_Function, Node_Procedure, Node_Object, Node_Field, @@ -240,6 +245,14 @@ package body Ortho_Front is type Node (<>); type Node_Acc is access Node; + + type Node_Array is array (Natural range <>) of Node_Acc; + + type Node_Map (Len : Natural) is record + Map : Node_Array (1 .. Len); + end record; + type Node_Map_Acc is access Node_Map; + type Node (Kind : Node_Kind) is record case Kind is when Decl_Keyword => @@ -299,6 +312,8 @@ package body Ortho_Front is Field_Fnode : O_Fnode; Field_Type : Node_Acc; Field_Next : Node_Acc; + -- Next entry in the field map (if the map exists). + Field_Hash_Next : Node_Acc; when Type_Signed | Type_Unsigned | Type_Float @@ -322,7 +337,11 @@ package body Ortho_Front is Access_Dtype : Node_Acc; when Type_Record | Type_Union => + -- Simply linked list of fields. Works well unless the + -- number of fields is too high. Record_Union_Fields : Node_Acc; + -- Hash map of fields (the key is the hash of the ident). + Record_Union_Map : Node_Map_Acc; when Type_Enum | Type_Boolean => Enum_Lits : Node_Acc; @@ -513,6 +532,42 @@ package body Ortho_Front is Unget_Char; end Scan_Comment; + function Get_Ident_Token return Token_Type + is + H : Hash_Type; + S : Syment_Acc; + N : Node_Acc; + begin + H := Token_Hash mod Hash_Max; + S := Symtable.Map (H); + while S /= null loop + if S.Hash = Token_Hash + and then Is_Equal (S.Ident, Token_Ident (1 .. Token_Idlen)) + then + -- This identifier is known. + Token_Sym := S; + + -- It may be a keyword. + if S.Name /= null then + N := Get_Decl (S); + if N.Kind = Decl_Keyword then + return N.Keyword; + end if; + end if; + + return Tok_Ident; + end if; + S := S.Next; + end loop; + Symtable.Map (H) := new Syment_Type' + (Hash => Token_Hash, + Ident => Get_Identifier (Token_Ident (1 .. Token_Idlen)), + Next => Symtable.Map (H), + Name => null); + Token_Sym := Symtable.Map (H); + return Tok_Ident; + end Get_Ident_Token; + -- Get the next token. function Get_Token return Token_Type is @@ -674,41 +729,7 @@ package body Ortho_Front is and (C /= '_'); end loop; Unget_Char; - declare - H : Hash_Type; - S : Syment_Acc; - N : Node_Acc; - begin - H := Token_Hash mod Hash_Max; - S := Symtable (H); - while S /= null loop - if S.Hash = Token_Hash - and then Is_Equal (S.Ident, - Token_Ident (1 .. Token_Idlen)) - then - -- This identifier is known. - Token_Sym := S; - - -- It may be a keyword. - if S.Name /= null then - N := Get_Decl (S); - if N.Kind = Decl_Keyword then - return N.Keyword; - end if; - end if; - - return Tok_Ident; - end if; - S := S.Next; - end loop; - Symtable (H) := new Syment_Type' - (Hash => Token_Hash, - Ident => Get_Identifier (Token_Ident (1 .. Token_Idlen)), - Next => Symtable (H), - Name => null); - Token_Sym := Symtable (H); - return Tok_Ident; - end; + return Get_Ident_Token; when others => Scan_Error ("Bad character:" & Integer'Image (Character'Pos (C)) @@ -844,8 +865,8 @@ package body Ortho_Front is Next => null, Name => null); H := Ent.Hash mod Hash_Max; - Ent.Next := Symtable (H); - Symtable (H) := Ent; + Ent.Next := Symtable.Map (H); + Symtable.Map (H) := Ent; return Ent; end New_Symbol; @@ -920,6 +941,16 @@ package body Ortho_Front is function Parse_Type return Node_Acc; + -- Return the index of FIELD in map MAP. + function Field_Map_Index (Map : Node_Map_Acc; Sym : Syment_Acc) + return Natural is + begin + return 1 + Natural (Sym.Hash mod Hash_Type (Map.Len)); + end Field_Map_Index; + + -- Grammar: + -- { ident : type ; } + -- end procedure Parse_Fields (Aggr_Type : Node_Acc; Constr : in out O_Element_List) is @@ -927,8 +958,10 @@ package body Ortho_Front is F : Syment_Acc; Last_Field : Node_Acc; Field : Node_Acc; + Num : Natural; begin Last_Field := null; + Num := 0; loop exit when Tok = Tok_End; @@ -943,7 +976,8 @@ package body Ortho_Front is Field_Ident => F, Field_Fnode => O_Fnode_Null, Field_Type => F_Type, - Field_Next => null); + Field_Next => null, + Field_Hash_Next => null); case Aggr_Type.Kind is when Type_Record => New_Record_Field (Constr, Field.Field_Fnode, F.Ident, @@ -954,15 +988,39 @@ package body Ortho_Front is when others => raise Program_Error; end case; + + -- Append field if Last_Field = null then Aggr_Type.Record_Union_Fields := Field; else Last_Field.Field_Next := Field; end if; Last_Field := Field; + + Num := Num + 1; + Expect (Tok_Semicolon, "';' expected"); Next_Token; end loop; + + -- Create a map if there are a lot of fields. + if Num > 16 then + declare + Map : Node_Map_Acc; + Idx : Natural; + begin + Map := new Node_Map'(Len => Num / 3, Map => (others => null)); + Aggr_Type.Record_Union_Map := Map; + Field := Aggr_Type.Record_Union_Fields; + while Field /= null loop + Idx := Field_Map_Index (Map, Field.Field_Ident); + Field.Field_Hash_Next := Map.Map (Idx); + Map.Map (Idx) := Field; + + Field := Field.Field_Next; + end loop; + end; + end if; end Parse_Fields; procedure Parse_Record_Type (Def : Node_Acc) @@ -1101,20 +1159,23 @@ package body Ortho_Front is -- Uncomplete record type. Res := new Node'(Kind => Type_Record, Type_Onode => O_Tnode_Null, - Record_Union_Fields => null); + Record_Union_Fields => null, + Record_Union_Map => null); New_Uncomplete_Record_Type (Res.Type_Onode); return Res; end if; Res := new Node'(Kind => Type_Record, Type_Onode => O_Tnode_Null, - Record_Union_Fields => null); + Record_Union_Fields => null, + Record_Union_Map => null); Parse_Record_Type (Res); when Tok_Union => Next_Token; Res := new Node'(Kind => Type_Union, Type_Onode => O_Tnode_Null, - Record_Union_Fields => null); + Record_Union_Fields => null, + Record_Union_Map => null); Parse_Union_Type (Res); when Tok_Boolean => @@ -1244,13 +1305,25 @@ package body Ortho_Front is function Find_Field_By_Name (Aggr_Type : Node_Acc) return Node_Acc is + Map : constant Node_Map_Acc := Aggr_Type.Record_Union_Map; Field : Node_Acc; begin - Field := Aggr_Type.Record_Union_Fields; - while Field /= null loop - exit when Field.Field_Ident = Token_Sym; - Field := Field.Field_Next; - end loop; + if Map /= null then + -- Look in the hash map if it is present. + Field := Map.Map (Field_Map_Index (Map, Token_Sym)); + while Field /= null loop + exit when Field.Field_Ident = Token_Sym; + Field := Field.Field_Hash_Next; + end loop; + else + -- Linear look. + Field := Aggr_Type.Record_Union_Fields; + while Field /= null loop + exit when Field.Field_Ident = Token_Sym; + Field := Field.Field_Next; + end loop; + end if; + if Field = null then Parse_Error ("no such field name"); end if; |