summaryrefslogtreecommitdiff
path: root/gcc/ada/set_targ.adb
blob: f25c9f84f812717a34aa3c61aaae358f2e82b820 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                             S E T _ T A R G                              --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--          Copyright (C) 2013-2016, Free Software Foundation, Inc.         --
--                                                                          --
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
-- for  more details.  You should have  received  a copy of the GNU General --
-- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
-- http://www.gnu.org/licenses for a complete copy of the license.          --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------

with Debug;    use Debug;
with Get_Targ; use Get_Targ;
with Opt;      use Opt;
with Output;   use Output;

with System;        use System;
with System.OS_Lib; use System.OS_Lib;

with Unchecked_Conversion;

package body Set_Targ is

   --------------------------------------------------------
   -- Data Used to Read/Write Target Dependent Info File --
   --------------------------------------------------------

   --  Table of string names written to file

   subtype Str is String;

   S_Bits_BE                    : constant Str := "Bits_BE";
   S_Bits_Per_Unit              : constant Str := "Bits_Per_Unit";
   S_Bits_Per_Word              : constant Str := "Bits_Per_Word";
   S_Bytes_BE                   : constant Str := "Bytes_BE";
   S_Char_Size                  : constant Str := "Char_Size";
   S_Double_Float_Alignment     : constant Str := "Double_Float_Alignment";
   S_Double_Scalar_Alignment    : constant Str := "Double_Scalar_Alignment";
   S_Double_Size                : constant Str := "Double_Size";
   S_Float_Size                 : constant Str := "Float_Size";
   S_Float_Words_BE             : constant Str := "Float_Words_BE";
   S_Int_Size                   : constant Str := "Int_Size";
   S_Long_Double_Size           : constant Str := "Long_Double_Size";
   S_Long_Long_Size             : constant Str := "Long_Long_Size";
   S_Long_Size                  : constant Str := "Long_Size";
   S_Maximum_Alignment          : constant Str := "Maximum_Alignment";
   S_Max_Unaligned_Field        : constant Str := "Max_Unaligned_Field";
   S_Pointer_Size               : constant Str := "Pointer_Size";
   S_Short_Enums                : constant Str := "Short_Enums";
   S_Short_Size                 : constant Str := "Short_Size";
   S_Strict_Alignment           : constant Str := "Strict_Alignment";
   S_System_Allocator_Alignment : constant Str := "System_Allocator_Alignment";
   S_Wchar_T_Size               : constant Str := "Wchar_T_Size";
   S_Words_BE                   : constant Str := "Words_BE";

   --  Table of names

   type AStr is access all String;

   DTN : constant array (Nat range <>) of AStr := (
          S_Bits_BE                    'Unrestricted_Access,
          S_Bits_Per_Unit              'Unrestricted_Access,
          S_Bits_Per_Word              'Unrestricted_Access,
          S_Bytes_BE                   'Unrestricted_Access,
          S_Char_Size                  'Unrestricted_Access,
          S_Double_Float_Alignment     'Unrestricted_Access,
          S_Double_Scalar_Alignment    'Unrestricted_Access,
          S_Double_Size                'Unrestricted_Access,
          S_Float_Size                 'Unrestricted_Access,
          S_Float_Words_BE             'Unrestricted_Access,
          S_Int_Size                   'Unrestricted_Access,
          S_Long_Double_Size           'Unrestricted_Access,
          S_Long_Long_Size             'Unrestricted_Access,
          S_Long_Size                  'Unrestricted_Access,
          S_Maximum_Alignment          'Unrestricted_Access,
          S_Max_Unaligned_Field        'Unrestricted_Access,
          S_Pointer_Size               'Unrestricted_Access,
          S_Short_Enums                'Unrestricted_Access,
          S_Short_Size                 'Unrestricted_Access,
          S_Strict_Alignment           'Unrestricted_Access,
          S_System_Allocator_Alignment 'Unrestricted_Access,
          S_Wchar_T_Size               'Unrestricted_Access,
          S_Words_BE                   'Unrestricted_Access);

   --  Table of corresponding value pointers

   DTV : constant array (Nat range <>) of System.Address := (
          Bits_BE                    'Address,
          Bits_Per_Unit              'Address,
          Bits_Per_Word              'Address,
          Bytes_BE                   'Address,
          Char_Size                  'Address,
          Double_Float_Alignment     'Address,
          Double_Scalar_Alignment    'Address,
          Double_Size                'Address,
          Float_Size                 'Address,
          Float_Words_BE             'Address,
          Int_Size                   'Address,
          Long_Double_Size           'Address,
          Long_Long_Size             'Address,
          Long_Size                  'Address,
          Maximum_Alignment          'Address,
          Max_Unaligned_Field        'Address,
          Pointer_Size               'Address,
          Short_Enums                'Address,
          Short_Size                 'Address,
          Strict_Alignment           'Address,
          System_Allocator_Alignment 'Address,
          Wchar_T_Size               'Address,
          Words_BE                   'Address);

   DTR : array (Nat range DTV'Range) of Boolean := (others => False);
   --  Table of flags used to validate that all values are present in file

   -----------------------
   -- Local Subprograms --
   -----------------------

   procedure Read_Target_Dependent_Values (File_Name : String);
   --  Read target dependent values from File_Name, and set the target
   --  dependent values (global variables) declared in this package.

   procedure Fail (E : String);
   pragma No_Return (Fail);
   --  Terminate program with fatal error message passed as parameter

   procedure Register_Float_Type
     (Name      : C_String;
      Digs      : Natural;
      Complex   : Boolean;
      Count     : Natural;
      Float_Rep : Float_Rep_Kind;
      Precision : Positive;
      Size      : Positive;
      Alignment : Natural);
   pragma Convention (C, Register_Float_Type);
   --  Call back to allow the back end to register available types. This call
   --  back makes entries in the FPT_Mode_Table for any floating point types
   --  reported by the back end. Name is the name of the type as a normal
   --  format Null-terminated string. Digs is the number of digits, where 0
   --  means it is not a fpt type (ignored during registration). Complex is
   --  non-zero if the type has real and imaginary parts (also ignored during
   --  registration). Count is the number of elements in a vector type (zero =
   --  not a vector, registration ignores vectors). Float_Rep shows the kind of
   --  floating-point type, and Precision, Size and Alignment are the precision
   --  size and alignment in bits.
   --
   --  The only types that are actually registered have Digs non-zero, Complex
   --  zero (false), and Count zero (not a vector). The Long_Double_Index
   --  variable below is updated to indicate the index at which a "long double"
   --  type can be found if it gets registered at all.

   Long_Double_Index : Integer := -1;
   --  Once all the floating point types have been registered, the index in
   --  FPT_Mode_Table at which "long double" can be found, if anywhere. A
   --  negative value means that no "long double" has been registered. This
   --  is useful to know whether we have a "long double" available at all and
   --  get at it's characteristics without having to search the FPT_Mode_Table
   --  when we need to decide which C type should be used as the basis for
   --  Long_Long_Float in Ada.

   function FPT_Mode_Index_For (Name : String) return Natural;
   --  Return the index in FPT_Mode_Table that designates the entry
   --  corresponding to the C type named Name. Raise Program_Error if
   --  there is no such entry.

   function FPT_Mode_Index_For (T : S_Float_Types) return Natural;
   --  Return the index in FPT_Mode_Table that designates the entry for
   --  a back-end type suitable as a basis to construct the standard Ada
   --  floating point type identified by T.

   ----------------
   -- C_Type_For --
   ----------------

   function C_Type_For (T : S_Float_Types) return String is

      --  ??? For now, we don't have a good way to tell the widest float
      --  type with hardware support. Basically, GCC knows the size of that
      --  type, but on x86-64 there often are two or three 128-bit types,
      --  one double extended that has 18 decimal digits, a 128-bit quad
      --  precision type with 33 digits and possibly a 128-bit decimal float
      --  type with 34 digits. As a workaround, we define Long_Long_Float as
      --  C's "long double" if that type exists and has at most 18 digits,
      --  or otherwise the same as Long_Float.

      Max_HW_Digs : constant := 18;
      --  Maximum hardware digits supported

   begin
      case T is
         when S_Float
            | S_Short_Float
         =>
            return "float";

         when S_Long_Float =>
            return "double";

         when S_Long_Long_Float =>
            if Long_Double_Index >= 0
              and then FPT_Mode_Table (Long_Double_Index).DIGS <= Max_HW_Digs
            then
               return "long double";
            else
               return "double";
            end if;
      end case;
   end C_Type_For;

   ----------
   -- Fail --
   ----------

   procedure Fail (E : String) is
      E_Fatal : constant := 4;
      --  Code for fatal error

   begin
      Write_Str (E);
      Write_Eol;
      OS_Exit (E_Fatal);
   end Fail;

   ------------------------
   -- FPT_Mode_Index_For --
   ------------------------

   function FPT_Mode_Index_For (Name : String) return Natural is
   begin
      for J in FPT_Mode_Table'First .. Num_FPT_Modes loop
         if FPT_Mode_Table (J).NAME.all = Name then
            return J;
         end if;
      end loop;

      raise Program_Error;
   end FPT_Mode_Index_For;

   function FPT_Mode_Index_For (T : S_Float_Types) return Natural is
   begin
      return FPT_Mode_Index_For (C_Type_For (T));
   end FPT_Mode_Index_For;

   -------------------------
   -- Register_Float_Type --
   -------------------------

   procedure Register_Float_Type
     (Name      : C_String;
      Digs      : Natural;
      Complex   : Boolean;
      Count     : Natural;
      Float_Rep : Float_Rep_Kind;
      Precision : Positive;
      Size      : Positive;
      Alignment : Natural)
   is
      T    : String (1 .. Name'Length);
      Last : Natural := 0;

      procedure Dump;
      --  Dump information given by the back end for the type to register

      ----------
      -- Dump --
      ----------

      procedure Dump is
      begin
         Write_Str ("type " & T (1 .. Last) & " is ");

         if Count > 0 then
            Write_Str ("array (1 .. ");
            Write_Int (Int (Count));

            if Complex then
               Write_Str (", 1 .. 2");
            end if;

            Write_Str (") of ");

         elsif Complex then
            Write_Str ("array (1 .. 2) of ");
         end if;

         if Digs > 0 then
            Write_Str ("digits ");
            Write_Int (Int (Digs));
            Write_Line (";");

            Write_Str ("pragma Float_Representation (");

            case Float_Rep is
               when AAMP        => Write_Str ("AAMP");
               when IEEE_Binary => Write_Str ("IEEE");
            end case;

            Write_Line (", " & T (1 .. Last) & ");");

         else
            Write_Str ("mod 2**");
            Write_Int (Int (Precision / Positive'Max (1, Count)));
            Write_Line (";");
         end if;

         if Precision = Size then
            Write_Str ("for " & T (1 .. Last) & "'Size use ");
            Write_Int (Int (Size));
            Write_Line (";");

         else
            Write_Str ("for " & T (1 .. Last) & "'Value_Size use ");
            Write_Int (Int (Precision));
            Write_Line (";");

            Write_Str ("for " & T (1 .. Last) & "'Object_Size use ");
            Write_Int (Int (Size));
            Write_Line (";");
         end if;

         Write_Str ("for " & T (1 .. Last) & "'Alignment use ");
         Write_Int (Int (Alignment / 8));
         Write_Line (";");
         Write_Eol;
      end Dump;

   --  Start of processing for Register_Float_Type

   begin
      --  Acquire name

      for J in T'Range loop
         T (J) := Name (Name'First + J - 1);

         if T (J) = ASCII.NUL then
            Last := J - 1;
            exit;
         end if;
      end loop;

      --  Dump info if debug flag set

      if Debug_Flag_Dot_B then
         Dump;
      end if;

      --  Acquire entry if non-vector non-complex fpt type (digits non-zero)

      if Digs > 0 and then not Complex and then Count = 0 then

         declare
            This_Name : constant String := T (1 .. Last);
         begin
            Num_FPT_Modes := Num_FPT_Modes + 1;
            FPT_Mode_Table (Num_FPT_Modes) :=
              (NAME      => new String'(This_Name),
               DIGS      => Digs,
               FLOAT_REP => Float_Rep,
               PRECISION => Precision,
               SIZE      => Size,
               ALIGNMENT => Alignment);

            if Long_Double_Index < 0 and then This_Name = "long double" then
               Long_Double_Index := Num_FPT_Modes;
            end if;
         end;
      end if;
   end Register_Float_Type;

   -----------------------------------
   -- Write_Target_Dependent_Values --
   -----------------------------------

   --  We do this at the System.Os_Lib level, since we have to do the read at
   --  that level anyway, so it is easier and more consistent to follow the
   --  same path for the write.

   procedure Write_Target_Dependent_Values is
      Fdesc  : File_Descriptor;
      OK     : Boolean;

      Buffer : String (1 .. 80);
      Buflen : Natural;
      --  Buffer used to build line one of file

      type ANat is access all Natural;
      --  Pointer to Nat or Pos value (it is harmless to treat Pos values and
      --  Nat values as Natural via Unchecked_Conversion).

      function To_ANat is new Unchecked_Conversion (Address, ANat);

      procedure AddC (C : Character);
      --  Add one character to buffer

      procedure AddN (N : Natural);
      --  Add representation of integer N to Buffer, updating Buflen. N
      --  must be less than 1000, and output is 3 characters with leading
      --  spaces as needed.

      procedure Write_Line;
      --  Output contents of Buffer (1 .. Buflen) followed by a New_Line,
      --  and set Buflen back to zero, ready to write next line.

      ----------
      -- AddC --
      ----------

      procedure AddC (C : Character) is
      begin
         Buflen := Buflen + 1;
         Buffer (Buflen) := C;
      end AddC;

      ----------
      -- AddN --
      ----------

      procedure AddN (N : Natural) is
      begin
         if N > 999 then
            raise Program_Error;
         end if;

         if N > 99 then
            AddC (Character'Val (48 + N / 100));
         else
            AddC (' ');
         end if;

         if N > 9 then
            AddC (Character'Val (48 + N / 10 mod 10));
         else
            AddC (' ');
         end if;

         AddC (Character'Val (48 + N mod 10));
      end AddN;

      ----------------
      -- Write_Line --
      ----------------

      procedure Write_Line is
      begin
         AddC (ASCII.LF);

         if Buflen /= Write (Fdesc, Buffer'Address, Buflen) then
            Delete_File (Target_Dependent_Info_Write_Name.all, OK);
            Fail ("disk full writing file "
                  & Target_Dependent_Info_Write_Name.all);
         end if;

         Buflen := 0;
      end Write_Line;

   --  Start of processing for Write_Target_Dependent_Values

   begin
      Fdesc :=
        Create_File (Target_Dependent_Info_Write_Name.all, Text);

      if Fdesc = Invalid_FD then
         Fail ("cannot create file " & Target_Dependent_Info_Write_Name.all);
      end if;

      --  Loop through values

      for J in DTN'Range loop

         --  Output name

         Buflen := DTN (J)'Length;
         Buffer (1 .. Buflen) := DTN (J).all;

         --  Line up values

         while Buflen < 26 loop
            AddC (' ');
         end loop;

         AddC (' ');
         AddC (' ');

         --  Output value and write line

         AddN (To_ANat (DTV (J)).all);
         Write_Line;
      end loop;

      --  Blank line to separate sections

      Write_Line;

      --  Write lines for registered FPT types

      for J in 1 .. Num_FPT_Modes loop
         declare
            E : FPT_Mode_Entry renames FPT_Mode_Table (J);
         begin
            Buflen := E.NAME'Last;
            Buffer (1 .. Buflen) := E.NAME.all;

            --  Pad out to line up values

            while Buflen < 11 loop
               AddC (' ');
            end loop;

            AddC (' ');
            AddC (' ');

            AddN (E.DIGS);
            AddC (' ');
            AddC (' ');

            case E.FLOAT_REP is
               when AAMP        => AddC ('A');
               when IEEE_Binary => AddC ('I');
            end case;

            AddC (' ');

            AddN (E.PRECISION);
            AddC (' ');

            AddN (E.ALIGNMENT);
            Write_Line;
         end;
      end loop;

      --  Close file

      Close (Fdesc, OK);

      if not OK then
         Fail ("disk full writing file "
               & Target_Dependent_Info_Write_Name.all);
      end if;
   end Write_Target_Dependent_Values;

   ----------------------------------
   -- Read_Target_Dependent_Values --
   ----------------------------------

   procedure Read_Target_Dependent_Values (File_Name : String) is
      File_Desc : File_Descriptor;
      N         : Natural;

      type ANat is access all Natural;
      --  Pointer to Nat or Pos value (it is harmless to treat Pos values
      --  as Nat via Unchecked_Conversion).

      function To_ANat is new Unchecked_Conversion (Address, ANat);

      VP : ANat;

      Buffer : String (1 .. 2000);
      Buflen : Natural;
      --  File information and length (2000 easily enough)

      Nam_Buf : String (1 .. 40);
      Nam_Len : Natural;

      procedure Check_Spaces;
      --  Checks that we have one or more spaces and skips them

      procedure FailN (S : String);
      --  Calls Fail adding " name in file xxx", where name is the currently
      --  gathered name in Nam_Buf, surrounded by quotes, and xxx is the
      --  name of the file.

      procedure Get_Name;
      --  Scan out name, leaving it in Nam_Buf with Nam_Len set. Calls
      --  Skip_Spaces to skip any following spaces. Note that the name is
      --  terminated by a sequence of at least two spaces.

      function Get_Nat return Natural;
      --  N on entry points to decimal integer, scan out decimal integer
      --  and return it, leaving N pointing to following space or LF.

      procedure Skip_Spaces;
      --  Skip past spaces

      ------------------
      -- Check_Spaces --
      ------------------

      procedure Check_Spaces is
      begin
         if N > Buflen or else Buffer (N) /= ' ' then
            FailN ("missing space for");
         end if;

         Skip_Spaces;
         return;
      end Check_Spaces;

      -----------
      -- FailN --
      -----------

      procedure FailN (S : String) is
      begin
         Fail (S & " """ & Nam_Buf (1 .. Nam_Len) & """ in file "
               & File_Name);
      end FailN;

      --------------
      -- Get_Name --
      --------------

      procedure Get_Name is
      begin
         Nam_Len := 0;

         --  Scan out name and put it in Nam_Buf

         loop
            if N > Buflen or else Buffer (N) = ASCII.LF then
               FailN ("incorrectly formatted line for");
            end if;

            --  Name is terminated by two blanks

            exit when N < Buflen and then Buffer (N .. N + 1) = "  ";

            Nam_Len := Nam_Len + 1;

            if Nam_Len > Nam_Buf'Last then
               Fail ("name too long");
            end if;

            Nam_Buf (Nam_Len) := Buffer (N);
            N := N + 1;
         end loop;

         Check_Spaces;
      end Get_Name;

      -------------
      -- Get_Nat --
      -------------

      function Get_Nat return Natural is
         Result : Natural := 0;

      begin
         loop
            if N > Buflen
              or else Buffer (N) not in '0' .. '9'
              or else Result > 999
            then
               FailN ("bad value for");
            end if;

            Result := Result * 10 + (Character'Pos (Buffer (N)) - 48);
            N := N + 1;

            exit when N <= Buflen
              and then (Buffer (N) = ASCII.LF or else Buffer (N) = ' ');
         end loop;

         return Result;
      end Get_Nat;

      -----------------
      -- Skip_Spaces --
      -----------------

      procedure Skip_Spaces is
      begin
         while N <= Buflen and Buffer (N) = ' ' loop
            N := N + 1;
         end loop;
      end Skip_Spaces;

   --  Start of processing for Read_Target_Dependent_Values

   begin
      File_Desc := Open_Read (File_Name, Text);

      if File_Desc = Invalid_FD then
         Fail ("cannot read file " & File_Name);
      end if;

      Buflen := Read (File_Desc, Buffer'Address, Buffer'Length);

      Close (File_Desc);

      if Buflen = Buffer'Length then
         Fail ("file is too long: " & File_Name);
      end if;

      --  Scan through file for properly formatted entries in first section

      N := 1;
      while N <= Buflen and then Buffer (N) /= ASCII.LF loop
         Get_Name;

         --  Validate name and get corresponding value pointer

         VP := null;

         for J in DTN'Range loop
            if DTN (J).all = Nam_Buf (1 .. Nam_Len) then
               VP := To_ANat (DTV (J));
               DTR (J) := True;
               exit;
            end if;
         end loop;

         if VP = null then
            FailN ("unrecognized name");
         end if;

         --  Scan out value

         VP.all := Get_Nat;

         if N > Buflen or else Buffer (N) /= ASCII.LF then
            FailN ("misformatted line for");
         end if;

         N := N + 1; -- skip LF
      end loop;

      --  Fall through this loop when all lines in first section read.
      --  Check that values have been supplied for all entries.

      for J in DTR'Range loop
         if not DTR (J) then
            Fail ("missing entry for " & DTN (J).all & " in file "
                  & File_Name);
         end if;
      end loop;

      --  Now acquire FPT entries

      if N >= Buflen then
         Fail ("missing entries for FPT modes in file " & File_Name);
      end if;

      if Buffer (N) = ASCII.LF then
         N := N + 1;
      else
         Fail ("missing blank line in file " & File_Name);
      end if;

      Num_FPT_Modes := 0;
      while N <= Buflen loop
         Get_Name;

         Num_FPT_Modes := Num_FPT_Modes + 1;

         declare
            E : FPT_Mode_Entry renames FPT_Mode_Table (Num_FPT_Modes);

         begin
            E.NAME := new String'(Nam_Buf (1 .. Nam_Len));

            if Long_Double_Index < 0 and then E.NAME.all = "long double" then
               Long_Double_Index := Num_FPT_Modes;
            end if;

            E.DIGS := Get_Nat;
            Check_Spaces;

            case Buffer (N) is
               when 'I'    =>
                  E.FLOAT_REP := IEEE_Binary;

               when 'A'    =>
                  E.FLOAT_REP := AAMP;

               when others =>
                  FailN ("bad float rep field for");
            end case;

            N := N + 1;
            Check_Spaces;

            E.PRECISION := Get_Nat;
            Check_Spaces;

            E.ALIGNMENT := Get_Nat;

            if Buffer (N) /= ASCII.LF then
               FailN ("junk at end of line for");
            end if;

            --  ??? We do not read E.SIZE, see Write_Target_Dependent_Values

            E.SIZE :=
              (E.PRECISION + E.ALIGNMENT - 1) / E.ALIGNMENT * E.ALIGNMENT;

            N := N + 1;
         end;
      end loop;
   end Read_Target_Dependent_Values;

--  Package Initialization, set target dependent values. This must be done
--  early on, before we start accessing various compiler packages, since
--  these values are used all over the place.

begin
   --  First step: see if the -gnateT switch is present. As we have noted,
   --  this has to be done very early, so can not depend on the normal circuit
   --  for reading switches and setting switches in Opt. The following code
   --  will set Opt.Target_Dependent_Info_Read_Name if the switch -gnateT=name
   --  is present in the options string.

   declare
      type Arg_Array is array (Nat) of Big_String_Ptr;
      type Arg_Array_Ptr is access Arg_Array;
      --  Types to access compiler arguments

      save_argc : Nat;
      pragma Import (C, save_argc);
      --  Saved value of argc (number of arguments), imported from misc.c

      save_argv : Arg_Array_Ptr;
      pragma Import (C, save_argv);
      --  Saved value of argv (argument pointers), imported from misc.c

      gnat_argc : Nat;
      gnat_argv : Arg_Array_Ptr;
      pragma Import (C, gnat_argc);
      pragma Import (C, gnat_argv);
      --  If save_argv is not set, default to gnat_argc/argv

      argc : Nat;
      argv : Arg_Array_Ptr;

      function Len_Arg (Arg : Big_String_Ptr) return Nat;
      --  Determine length of argument Arg (a nul terminated C string).

      -------------
      -- Len_Arg --
      -------------

      function Len_Arg (Arg : Big_String_Ptr) return Nat is
      begin
         for J in 1 .. Nat'Last loop
            if Arg (Natural (J)) = ASCII.NUL then
               return J - 1;
            end if;
         end loop;

         raise Program_Error;
      end Len_Arg;

   begin
      if save_argv /= null then
         argv := save_argv;
         argc := save_argc;
      else
         --  Case of a non gcc compiler, e.g. gnat2why or gnat2scil
         argv := gnat_argv;
         argc := gnat_argc;
      end if;

      --  Loop through arguments looking for -gnateT, also look for -gnatd.b

      for Arg in 1 .. argc - 1 loop
         declare
            Argv_Ptr : constant Big_String_Ptr := argv (Arg);
            Argv_Len : constant Nat            := Len_Arg (Argv_Ptr);

         begin
            if Argv_Len > 8
              and then Argv_Ptr (1 .. 8) = "-gnateT="
            then
               Opt.Target_Dependent_Info_Read_Name :=
                 new String'(Argv_Ptr (9 .. Natural (Argv_Len)));

            elsif Argv_Len >= 8
              and then Argv_Ptr (1 .. 8) = "-gnatd.b"
            then
               Debug_Flag_Dot_B := True;
            end if;
         end;
      end loop;
   end;

   --  Case of reading the target dependent values from file

   --  This is bit more complex than might be expected, because it has to be
   --  done very early. All kinds of packages depend on these values, and we
   --  can't wait till the normal processing of reading command line switches
   --  etc to read the file. We do this at the System.OS_Lib level since it is
   --  too early to be using Osint directly.

   if Opt.Target_Dependent_Info_Read_Name /= null then
      Read_Target_Dependent_Values (Target_Dependent_Info_Read_Name.all);
   else
      --  If the back-end comes with a target config file, then use it
      --  to set the values

      declare
         Back_End_Config_File : constant String_Ptr :=
           Get_Back_End_Config_File;
      begin
         if Back_End_Config_File /= null then
            Read_Target_Dependent_Values (Back_End_Config_File.all);

         --  Otherwise we get all values from the back end directly

         else
            Bits_BE                    := Get_Bits_BE;
            Bits_Per_Unit              := Get_Bits_Per_Unit;
            Bits_Per_Word              := Get_Bits_Per_Word;
            Bytes_BE                   := Get_Bytes_BE;
            Char_Size                  := Get_Char_Size;
            Double_Float_Alignment     := Get_Double_Float_Alignment;
            Double_Scalar_Alignment    := Get_Double_Scalar_Alignment;
            Float_Words_BE             := Get_Float_Words_BE;
            Int_Size                   := Get_Int_Size;
            Long_Long_Size             := Get_Long_Long_Size;
            Long_Size                  := Get_Long_Size;
            Maximum_Alignment          := Get_Maximum_Alignment;
            Max_Unaligned_Field        := Get_Max_Unaligned_Field;
            Pointer_Size               := Get_Pointer_Size;
            Short_Enums                := Get_Short_Enums;
            Short_Size                 := Get_Short_Size;
            Strict_Alignment           := Get_Strict_Alignment;
            System_Allocator_Alignment := Get_System_Allocator_Alignment;
            Wchar_T_Size               := Get_Wchar_T_Size;
            Words_BE                   := Get_Words_BE;

            --  Let the back-end register its floating point types and compute
            --  the sizes of our standard types from there:

            Num_FPT_Modes := 0;
            Register_Back_End_Types (Register_Float_Type'Access);

            declare
               T : FPT_Mode_Entry renames
                 FPT_Mode_Table (FPT_Mode_Index_For (S_Float));
            begin
               Float_Size := Pos (T.SIZE);
            end;

            declare
               T : FPT_Mode_Entry renames
                 FPT_Mode_Table (FPT_Mode_Index_For (S_Long_Float));
            begin
               Double_Size := Pos (T.SIZE);
            end;

            declare
               T : FPT_Mode_Entry renames
                 FPT_Mode_Table (FPT_Mode_Index_For (S_Long_Long_Float));
            begin
               Long_Double_Size := Pos (T.SIZE);
            end;

         end if;
      end;
   end if;
end Set_Targ;