re PR rtl-optimization/34522 (inefficient code for long long multiply when only low...
[official-gcc.git] / gcc / ada / fmap.adb
blob8f286b3b6f7b528149004c5066c4424cb60a5439
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- F M A P --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2001-2007, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
26 with Opt; use Opt;
27 with Osint; use Osint;
28 with Output; use Output;
29 with Table;
30 with Types; use Types;
32 with System.OS_Lib; use System.OS_Lib;
34 with Unchecked_Conversion;
36 with GNAT.HTable;
38 package body Fmap is
40 subtype Big_String is String (Positive);
41 type Big_String_Ptr is access all Big_String;
43 function To_Big_String_Ptr is new Unchecked_Conversion
44 (Source_Buffer_Ptr, Big_String_Ptr);
46 Max_Buffer : constant := 1_500;
47 Buffer : String (1 .. Max_Buffer);
48 -- Used to bufferize output when writing to a new mapping file
50 Buffer_Last : Natural := 0;
51 -- Index of last valid character in Buffer
53 type Mapping is record
54 Uname : Unit_Name_Type;
55 Fname : File_Name_Type;
56 end record;
58 package File_Mapping is new Table.Table (
59 Table_Component_Type => Mapping,
60 Table_Index_Type => Int,
61 Table_Low_Bound => 0,
62 Table_Initial => 1_000,
63 Table_Increment => 1_000,
64 Table_Name => "Fmap.File_Mapping");
65 -- Mapping table to map unit names to file names
67 package Path_Mapping is new Table.Table (
68 Table_Component_Type => Mapping,
69 Table_Index_Type => Int,
70 Table_Low_Bound => 0,
71 Table_Initial => 1_000,
72 Table_Increment => 1_000,
73 Table_Name => "Fmap.Path_Mapping");
74 -- Mapping table to map file names to path names
76 type Header_Num is range 0 .. 1_000;
78 function Hash (F : Unit_Name_Type) return Header_Num;
79 -- Function used to compute hash of unit name
81 No_Entry : constant Int := -1;
82 -- Signals no entry in following table
84 package Unit_Hash_Table is new GNAT.HTable.Simple_HTable (
85 Header_Num => Header_Num,
86 Element => Int,
87 No_Element => No_Entry,
88 Key => Unit_Name_Type,
89 Hash => Hash,
90 Equal => "=");
91 -- Hash table to map unit names to file names. Used in conjunction with
92 -- table File_Mapping above.
94 function Hash (F : File_Name_Type) return Header_Num;
95 -- Function used to compute hash of file name
97 package File_Hash_Table is new GNAT.HTable.Simple_HTable (
98 Header_Num => Header_Num,
99 Element => Int,
100 No_Element => No_Entry,
101 Key => File_Name_Type,
102 Hash => Hash,
103 Equal => "=");
104 -- Hash table to map file names to path names. Used in conjunction with
105 -- table Path_Mapping above.
107 Last_In_Table : Int := 0;
109 package Forbidden_Names is new GNAT.HTable.Simple_HTable (
110 Header_Num => Header_Num,
111 Element => Boolean,
112 No_Element => False,
113 Key => File_Name_Type,
114 Hash => Hash,
115 Equal => "=");
117 -----------------------------
118 -- Add_Forbidden_File_Name --
119 -----------------------------
121 procedure Add_Forbidden_File_Name (Name : File_Name_Type) is
122 begin
123 Forbidden_Names.Set (Name, True);
124 end Add_Forbidden_File_Name;
126 ---------------------
127 -- Add_To_File_Map --
128 ---------------------
130 procedure Add_To_File_Map
131 (Unit_Name : Unit_Name_Type;
132 File_Name : File_Name_Type;
133 Path_Name : File_Name_Type)
135 Unit_Entry : constant Int := Unit_Hash_Table.Get (Unit_Name);
136 File_Entry : constant Int := File_Hash_Table.Get (File_Name);
137 begin
138 if Unit_Entry = No_Entry or else
139 File_Mapping.Table (Unit_Entry).Fname /= File_Name
140 then
141 File_Mapping.Increment_Last;
142 Unit_Hash_Table.Set (Unit_Name, File_Mapping.Last);
143 File_Mapping.Table (File_Mapping.Last) :=
144 (Uname => Unit_Name, Fname => File_Name);
145 end if;
147 if File_Entry = No_Entry or else
148 Path_Mapping.Table (File_Entry).Fname /= Path_Name
149 then
150 Path_Mapping.Increment_Last;
151 File_Hash_Table.Set (File_Name, Path_Mapping.Last);
152 Path_Mapping.Table (Path_Mapping.Last) :=
153 (Uname => Unit_Name, Fname => Path_Name);
154 end if;
155 end Add_To_File_Map;
157 ----------
158 -- Hash --
159 ----------
161 function Hash (F : File_Name_Type) return Header_Num is
162 begin
163 return Header_Num (Int (F) rem Header_Num'Range_Length);
164 end Hash;
166 function Hash (F : Unit_Name_Type) return Header_Num is
167 begin
168 return Header_Num (Int (F) rem Header_Num'Range_Length);
169 end Hash;
171 ----------------
172 -- Initialize --
173 ----------------
175 procedure Initialize (File_Name : String) is
176 Src : Source_Buffer_Ptr;
177 Hi : Source_Ptr;
178 BS : Big_String_Ptr;
179 SP : String_Ptr;
181 First : Positive := 1;
182 Last : Natural := 0;
184 Uname : Unit_Name_Type;
185 Fname : File_Name_Type;
186 Pname : File_Name_Type;
188 procedure Empty_Tables;
189 -- Remove all entries in case of incorrect mapping file
191 function Find_File_Name return File_Name_Type;
192 -- Return Error_File_Name for "/", otherwise call Name_Find
193 -- What is this about, explanation required ???
195 function Find_Unit_Name return Unit_Name_Type;
196 -- Return Error_Unit_Name for "/", otherwise call Name_Find
197 -- Even more mysterious??? function appeared when Find_Name was split
198 -- for the two types, but this routine is definitely called!
200 procedure Get_Line;
201 -- Get a line from the mapping file
203 procedure Report_Truncated;
204 -- Report a warning when the mapping file is truncated
205 -- (number of lines is not a multiple of 3).
207 ------------------
208 -- Empty_Tables --
209 ------------------
211 procedure Empty_Tables is
212 begin
213 Unit_Hash_Table.Reset;
214 File_Hash_Table.Reset;
215 Path_Mapping.Set_Last (0);
216 File_Mapping.Set_Last (0);
217 Last_In_Table := 0;
218 end Empty_Tables;
220 --------------------
221 -- Find_File_Name --
222 --------------------
224 -- Why is only / illegal, why not \ on windows ???
226 function Find_File_Name return File_Name_Type is
227 begin
228 if Name_Buffer (1 .. Name_Len) = "/" then
229 return Error_File_Name;
230 else
231 return Name_Find;
232 end if;
233 end Find_File_Name;
235 --------------------
236 -- Find_Unit_Name --
237 --------------------
239 function Find_Unit_Name return Unit_Name_Type is
240 begin
241 return Unit_Name_Type (Find_File_Name);
242 -- very odd ???
243 end Find_Unit_Name;
245 --------------
246 -- Get_Line --
247 --------------
249 procedure Get_Line is
250 use ASCII;
252 begin
253 First := Last + 1;
255 -- If not at the end of file, skip the end of line
257 while First < SP'Last
258 and then (SP (First) = CR
259 or else SP (First) = LF
260 or else SP (First) = EOF)
261 loop
262 First := First + 1;
263 end loop;
265 -- If not at the end of file, find the end of this new line
267 if First < SP'Last and then SP (First) /= EOF then
268 Last := First;
270 while Last < SP'Last
271 and then SP (Last + 1) /= CR
272 and then SP (Last + 1) /= LF
273 and then SP (Last + 1) /= EOF
274 loop
275 Last := Last + 1;
276 end loop;
278 end if;
279 end Get_Line;
281 ----------------------
282 -- Report_Truncated --
283 ----------------------
285 procedure Report_Truncated is
286 begin
287 Write_Str ("warning: mapping file """);
288 Write_Str (File_Name);
289 Write_Line (""" is truncated");
290 end Report_Truncated;
292 -- Start of processing for Initialize
294 begin
295 Empty_Tables;
296 Name_Len := File_Name'Length;
297 Name_Buffer (1 .. Name_Len) := File_Name;
298 Read_Source_File (Name_Enter, 0, Hi, Src, Config);
300 if Src = null then
301 Write_Str ("warning: could not read mapping file """);
302 Write_Str (File_Name);
303 Write_Line ("""");
305 else
306 BS := To_Big_String_Ptr (Src);
307 SP := BS (1 .. Natural (Hi))'Unrestricted_Access;
309 loop
310 -- Get the unit name
312 Get_Line;
314 -- Exit if end of file has been reached
316 exit when First > Last;
318 if (Last < First + 2) or else (SP (Last - 1) /= '%')
319 or else (SP (Last) /= 's' and then SP (Last) /= 'b')
320 then
321 Write_Str ("warning: mapping file """);
322 Write_Str (File_Name);
323 Write_Line (""" is incorrectly formatted");
324 Empty_Tables;
325 return;
326 end if;
328 Name_Len := Last - First + 1;
329 Name_Buffer (1 .. Name_Len) := SP (First .. Last);
330 Uname := Find_Unit_Name;
332 -- Get the file name
334 Get_Line;
336 -- If end of line has been reached, file is truncated
338 if First > Last then
339 Report_Truncated;
340 Empty_Tables;
341 return;
342 end if;
344 Name_Len := Last - First + 1;
345 Name_Buffer (1 .. Name_Len) := SP (First .. Last);
346 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
347 Fname := Find_File_Name;
349 -- Get the path name
351 Get_Line;
353 -- If end of line has been reached, file is truncated
355 if First > Last then
356 Report_Truncated;
357 Empty_Tables;
358 return;
359 end if;
361 Name_Len := Last - First + 1;
362 Name_Buffer (1 .. Name_Len) := SP (First .. Last);
363 Pname := Find_File_Name;
365 -- Add the mappings for this unit name
367 Add_To_File_Map (Uname, Fname, Pname);
368 end loop;
369 end if;
371 -- Record the length of the two mapping tables
373 Last_In_Table := File_Mapping.Last;
374 end Initialize;
376 ----------------------
377 -- Mapped_File_Name --
378 ----------------------
380 function Mapped_File_Name (Unit : Unit_Name_Type) return File_Name_Type is
381 The_Index : constant Int := Unit_Hash_Table.Get (Unit);
383 begin
384 if The_Index = No_Entry then
385 return No_File;
386 else
387 return File_Mapping.Table (The_Index).Fname;
388 end if;
389 end Mapped_File_Name;
391 ----------------------
392 -- Mapped_Path_Name --
393 ----------------------
395 function Mapped_Path_Name (File : File_Name_Type) return File_Name_Type is
396 Index : Int := No_Entry;
398 begin
399 if Forbidden_Names.Get (File) then
400 return Error_File_Name;
401 end if;
403 Index := File_Hash_Table.Get (File);
405 if Index = No_Entry then
406 return No_File;
407 else
408 return Path_Mapping.Table (Index).Fname;
409 end if;
410 end Mapped_Path_Name;
412 --------------------------------
413 -- Remove_Forbidden_File_Name --
414 --------------------------------
416 procedure Remove_Forbidden_File_Name (Name : File_Name_Type) is
417 begin
418 Forbidden_Names.Set (Name, False);
419 end Remove_Forbidden_File_Name;
421 ------------------
422 -- Reset_Tables --
423 ------------------
425 procedure Reset_Tables is
426 begin
427 File_Mapping.Init;
428 Path_Mapping.Init;
429 Unit_Hash_Table.Reset;
430 File_Hash_Table.Reset;
431 Forbidden_Names.Reset;
432 Last_In_Table := 0;
433 end Reset_Tables;
435 -------------------------
436 -- Update_Mapping_File --
437 -------------------------
439 procedure Update_Mapping_File (File_Name : String) is
440 File : File_Descriptor;
441 N_Bytes : Integer;
443 File_Entry : Int;
445 Status : Boolean;
446 -- For the call to Close
448 procedure Put_Line (Name : Name_Id);
449 -- Put Name as a line in the Mapping File
451 --------------
452 -- Put_Line --
453 --------------
455 procedure Put_Line (Name : Name_Id) is
456 begin
457 Get_Name_String (Name);
459 -- If the Buffer is full, write it to the file
461 if Buffer_Last + Name_Len + 1 > Buffer'Last then
462 N_Bytes := Write (File, Buffer (1)'Address, Buffer_Last);
464 if N_Bytes < Buffer_Last then
465 Fail ("disk full");
466 end if;
468 Buffer_Last := 0;
469 end if;
471 -- Add the line to the Buffer
473 Buffer (Buffer_Last + 1 .. Buffer_Last + Name_Len) :=
474 Name_Buffer (1 .. Name_Len);
475 Buffer_Last := Buffer_Last + Name_Len + 1;
476 Buffer (Buffer_Last) := ASCII.LF;
477 end Put_Line;
479 -- Start of Update_Mapping_File
481 begin
483 -- Only Update if there are new entries in the mappings
485 if Last_In_Table < File_Mapping.Last then
487 -- If the tables have been emptied, recreate the file.
488 -- Otherwise, append to it.
490 if Last_In_Table = 0 then
491 declare
492 Discard : Boolean;
493 pragma Warnings (Off, Discard);
494 begin
495 Delete_File (File_Name, Discard);
496 end;
498 File := Create_File (File_Name, Binary);
500 else
501 File := Open_Read_Write (Name => File_Name, Fmode => Binary);
502 end if;
504 if File /= Invalid_FD then
505 if Last_In_Table > 0 then
506 Lseek (File, 0, Seek_End);
507 end if;
509 for Unit in Last_In_Table + 1 .. File_Mapping.Last loop
510 Put_Line (Name_Id (File_Mapping.Table (Unit).Uname));
511 Put_Line (Name_Id (File_Mapping.Table (Unit).Fname));
512 File_Entry :=
513 File_Hash_Table.Get (File_Mapping.Table (Unit).Fname);
514 Put_Line (Name_Id (Path_Mapping.Table (File_Entry).Fname));
515 end loop;
517 -- Before closing the file, write the buffer to the file. It is
518 -- guaranteed that the Buffer is not empty, because Put_Line has
519 -- been called at least 3 times, and after a call to Put_Line, the
520 -- Buffer is not empty.
522 N_Bytes := Write (File, Buffer (1)'Address, Buffer_Last);
524 if N_Bytes < Buffer_Last then
525 Fail ("disk full");
526 end if;
528 Close (File, Status);
530 if not Status then
531 Fail ("disk full");
532 end if;
534 elsif not Quiet_Output then
535 Write_Str ("warning: could not open mapping file """);
536 Write_Str (File_Name);
537 Write_Line (""" for update");
538 end if;
540 end if;
541 end Update_Mapping_File;
543 end Fmap;