hppa: Revise REG+D address support to allow long displacements before reload
[official-gcc.git] / gcc / ada / fmap.adb
blob6cc5ca22438baf9990ff985a39f56c88cd29b573
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- F M A P --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2001-2023, 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 pragma Warnings (Off);
33 -- This package is used also by gnatcoll
34 with System.OS_Lib; use System.OS_Lib;
35 pragma Warnings (On);
37 with GNAT.HTable;
39 package body Fmap is
41 No_Mapping_File : Boolean := False;
42 -- Set to True when the specified mapping file cannot be read in
43 -- procedure Initialize, so that no attempt is made to open the mapping
44 -- file in procedure Update_Mapping_File.
46 Max_Buffer : constant := 1_500;
47 Buffer : String (1 .. Max_Buffer);
48 -- Used to buffer 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) mod 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) mod Header_Num'Range_Length);
169 end Hash;
171 ----------------
172 -- Initialize --
173 ----------------
175 procedure Initialize (File_Name : String) is
176 FD : File_Descriptor;
177 Src : Source_Buffer_Ptr;
178 Hi : Source_Ptr;
180 First : Source_Ptr := 1;
181 Last : Source_Ptr := 0;
183 Uname : Unit_Name_Type;
184 Fname : File_Name_Type;
185 Pname : File_Name_Type;
187 procedure Empty_Tables;
188 -- Remove all entries in case of incorrect mapping file
190 function Find_File_Name return File_Name_Type;
191 -- Return Error_File_Name if the name buffer contains "/", otherwise
192 -- call Name_Find. "/" is the path name in the mapping file to indicate
193 -- that a source has been suppressed, and thus should not be found by
194 -- the compiler.
196 function Find_Unit_Name return Unit_Name_Type;
197 -- Return the unit name in the name buffer. Return Error_Unit_Name if
198 -- the name buffer contains "/".
200 procedure Get_Line;
201 -- Get a line from the mapping file, where a line is Src (First .. Last)
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 function Find_File_Name return File_Name_Type is
225 begin
226 if Name_Buffer (1 .. Name_Len) = "/" then
228 -- A path name of "/" is the indication that the source has been
229 -- "suppressed". Return Error_File_Name so that the compiler does
230 -- not find the source, even if it is in the include path.
232 return Error_File_Name;
234 else
235 return Name_Find;
236 end if;
237 end Find_File_Name;
239 --------------------
240 -- Find_Unit_Name --
241 --------------------
243 function Find_Unit_Name return Unit_Name_Type is
244 begin
245 return Unit_Name_Type (Find_File_Name);
246 end Find_Unit_Name;
248 --------------
249 -- Get_Line --
250 --------------
252 procedure Get_Line is
253 use ASCII;
255 begin
256 First := Last + 1;
258 -- If not at the end of file, skip the end of line
260 while First < Src'Last
261 and then (Src (First) = CR
262 or else Src (First) = LF
263 or else Src (First) = EOF)
264 loop
265 First := First + 1;
266 end loop;
268 -- If not at the end of file, find the end of this new line
270 if First < Src'Last and then Src (First) /= EOF then
271 Last := First;
273 while Last < Src'Last
274 and then Src (Last + 1) /= CR
275 and then Src (Last + 1) /= LF
276 and then Src (Last + 1) /= EOF
277 loop
278 Last := Last + 1;
279 end loop;
281 end if;
282 end Get_Line;
284 ----------------------
285 -- Report_Truncated --
286 ----------------------
288 procedure Report_Truncated is
289 begin
290 Write_Str ("warning: mapping file """);
291 Write_Str (File_Name);
292 Write_Line (""" is truncated");
293 end Report_Truncated;
295 -- Start of processing for Initialize
297 begin
298 Empty_Tables;
299 Read_Source_File (Name_Enter (File_Name), 1, Hi, Src, FD, Config);
301 if Null_Source_Buffer_Ptr (Src) then
302 if FD = Osint.Null_FD then
303 Write_Str ("warning: could not locate mapping file """);
304 else
305 Write_Str ("warning: no read access for mapping file """);
306 end if;
308 Write_Str (File_Name);
309 Write_Line ("""");
310 No_Mapping_File := True;
312 else
313 loop
314 -- Get the unit name
316 Get_Line;
318 -- Exit if end of file has been reached
320 exit when First > Last;
322 if Last < First + 2 or else Src (Last - 1) /= '%'
323 or else (Src (Last) /= 's' and then Src (Last) /= 'b')
324 then
325 Write_Line
326 ("warning: mapping file """ & File_Name &
327 """ is incorrectly formatted");
328 Write_Line ("Line = """ & String (Src (First .. Last)) & '"');
329 Empty_Tables;
330 return;
331 end if;
333 Name_Len := Integer (Last - First + 1);
334 Name_Buffer (1 .. Name_Len) := String (Src (First .. Last));
335 Uname := Find_Unit_Name;
337 -- Get the file name
339 Get_Line;
341 -- If end of line has been reached, file is truncated
343 if First > Last then
344 Report_Truncated;
345 Empty_Tables;
346 return;
347 end if;
349 Name_Len := Integer (Last - First + 1);
350 Name_Buffer (1 .. Name_Len) := String (Src (First .. Last));
351 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
352 Fname := Find_File_Name;
354 -- Get the path name
356 Get_Line;
358 -- If end of line has been reached, file is truncated
360 if First > Last then
361 Report_Truncated;
362 Empty_Tables;
363 return;
364 end if;
366 Name_Len := Integer (Last - First + 1);
367 Name_Buffer (1 .. Name_Len) := String (Src (First .. Last));
368 Pname := Find_File_Name;
370 -- Add the mappings for this unit name
372 Add_To_File_Map (Uname, Fname, Pname);
373 end loop;
374 end if;
376 -- Record the length of the two mapping tables
378 Last_In_Table := File_Mapping.Last;
379 end Initialize;
381 ----------------------
382 -- Mapped_File_Name --
383 ----------------------
385 function Mapped_File_Name (Unit : Unit_Name_Type) return File_Name_Type is
386 The_Index : constant Int := Unit_Hash_Table.Get (Unit);
388 begin
389 if The_Index = No_Entry then
390 return No_File;
391 else
392 return File_Mapping.Table (The_Index).Fname;
393 end if;
394 end Mapped_File_Name;
396 ----------------------
397 -- Mapped_Path_Name --
398 ----------------------
400 function Mapped_Path_Name (File : File_Name_Type) return File_Name_Type is
401 Index : Int := No_Entry;
403 begin
404 if Forbidden_Names.Get (File) then
405 return Error_File_Name;
406 end if;
408 Index := File_Hash_Table.Get (File);
410 if Index = No_Entry then
411 return No_File;
412 else
413 return Path_Mapping.Table (Index).Fname;
414 end if;
415 end Mapped_Path_Name;
417 ------------------
418 -- Reset_Tables --
419 ------------------
421 procedure Reset_Tables is
422 begin
423 File_Mapping.Init;
424 Path_Mapping.Init;
425 Unit_Hash_Table.Reset;
426 File_Hash_Table.Reset;
427 Forbidden_Names.Reset;
428 Last_In_Table := 0;
429 end Reset_Tables;
431 -------------------------
432 -- Update_Mapping_File --
433 -------------------------
435 procedure Update_Mapping_File (File_Name : String) is
436 File : File_Descriptor;
437 N_Bytes : Integer;
439 File_Entry : Int;
441 Status : Boolean;
442 -- For the call to Close
444 procedure Put_Line (Name : Name_Id);
445 -- Put Name as a line in the Mapping File
447 --------------
448 -- Put_Line --
449 --------------
451 procedure Put_Line (Name : Name_Id) is
452 begin
453 Get_Name_String (Name);
455 -- If the Buffer is full, write it to the file
457 if Buffer_Last + Name_Len + 1 > Buffer'Last then
458 N_Bytes := Write (File, Buffer (1)'Address, Buffer_Last);
460 if N_Bytes < Buffer_Last then
461 Fail ("disk full");
462 end if;
464 Buffer_Last := 0;
465 end if;
467 -- Add the line to the Buffer
469 Buffer (Buffer_Last + 1 .. Buffer_Last + Name_Len) :=
470 Name_Buffer (1 .. Name_Len);
471 Buffer_Last := Buffer_Last + Name_Len + 1;
472 Buffer (Buffer_Last) := ASCII.LF;
473 end Put_Line;
475 -- Start of processing for Update_Mapping_File
477 begin
478 -- If the mapping file could not be read, then it will not be possible
479 -- to update it.
481 if No_Mapping_File then
482 return;
483 end if;
484 -- Only Update if there are new entries in the mappings
486 if Last_In_Table < File_Mapping.Last then
488 File := Open_Read_Write (Name => File_Name, Fmode => Binary);
490 if File /= Invalid_FD then
491 if Last_In_Table > 0 then
492 Lseek (File, 0, Seek_End);
493 end if;
495 for Unit in Last_In_Table + 1 .. File_Mapping.Last loop
496 Put_Line (Name_Id (File_Mapping.Table (Unit).Uname));
497 Put_Line (Name_Id (File_Mapping.Table (Unit).Fname));
498 File_Entry :=
499 File_Hash_Table.Get (File_Mapping.Table (Unit).Fname);
500 Put_Line (Name_Id (Path_Mapping.Table (File_Entry).Fname));
501 end loop;
503 -- Before closing the file, write the buffer to the file. It is
504 -- guaranteed that the Buffer is not empty, because Put_Line has
505 -- been called at least 3 times, and after a call to Put_Line, the
506 -- Buffer is not empty.
508 N_Bytes := Write (File, Buffer (1)'Address, Buffer_Last);
510 if N_Bytes < Buffer_Last then
511 Fail ("disk full");
512 end if;
514 Close (File, Status);
516 if not Status then
517 Fail ("disk full");
518 end if;
520 elsif not Quiet_Output then
521 Write_Str ("warning: could not open mapping file """);
522 Write_Str (File_Name);
523 Write_Line (""" for update");
524 end if;
526 end if;
527 end Update_Mapping_File;
529 end Fmap;