1 /**
2  * Configure the back end (optimizer and code generator)
3  *
4  * Compiler implementation of the
5  * $(LINK2 https://www.dlang.org, D programming language).
6  *
7  * Copyright:   Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved
8  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
9  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
10  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/backconfig.d, backend/backconfig.d)
11  */
12 
13 module dmd.backend.backconfig;
14 
15 import core.stdc.stdio;
16 
17 import dmd.backend.cdef;
18 import dmd.backend.cc;
19 import dmd.backend.code;
20 import dmd.backend.global;
21 import dmd.backend.ty;
22 import dmd.backend.type;
23 
24 import dmd.backend.dwarfdbginf;
25 extern (C++):
26 
27 nothrow:
28 @safe:
29 
30 version (MARS)
31 {
32     void ph_init();
33 }
34 
35 /**************************************
36  * Initialize configuration for backend.
37  * Params:
38     model         = 32 for 32 bit code,
39                     64 for 64 bit code,
40                     set bit 0 to generate MS-COFF instead of OMF on Windows
41     exe           = true for exe file,
42                     false for dll or shared library (generate PIC code)
43     trace         =  add profiling code
44     nofloat       = do not pull in floating point code
45     vasm          = print generated assembler for each function
46     verbose       = verbose compile
47     optimize      = optimize code
48     symdebug      = add symbolic debug information,
49                     1 for D,
50                     2 for fake it with C symbolic debug info
51     alwaysframe   = always create standard function frame
52     stackstomp    = add stack stomping code
53     avx           = use AVX instruction set (0, 1, 2)
54     pic           = position independence level (0, 1, 2)
55     useModuleInfo = implement ModuleInfo
56     useTypeInfo   = implement TypeInfo
57     useExceptions = implement exception handling
58     dwarf         = DWARF version used
59     _version      = Compiler version
60     exefmt        = Executable file format
61     generatedMain = a main entrypoint is generated
62  */
63 public
64 @trusted
65 extern (C) void out_config_init(
66         int model,
67         bool exe,
68         bool trace,
69         bool nofloat,
70         bool vasm,      // print generated assembler for each function
71         bool verbose,
72         bool optimize,
73         int symdebug,
74         bool alwaysframe,
75         bool stackstomp,
76         ubyte avx,
77         ubyte pic,
78         bool useModuleInfo,
79         bool useTypeInfo,
80         bool useExceptions,
81         ubyte dwarf,
82         string _version,
83         exefmt_t exefmt,
84         bool generatedMain      // a main entrypoint is generated
85         )
86 {
87 version (MARS)
88 {
89     //printf("out_config_init()\n");
90 
91     auto cfg = &config;
92 
93     cfg._version = _version;
94     if (!cfg.target_cpu)
95     {   cfg.target_cpu = TARGET_PentiumPro;
96         cfg.target_scheduler = cfg.target_cpu;
97     }
98     cfg.fulltypes = CVNONE;
99     cfg.fpxmmregs = false;
100     cfg.inline8087 = 1;
101     cfg.memmodel = 0;
102     cfg.flags |= CFGuchar;   // make sure TYchar is unsigned
103     cfg.exe = exefmt;
104     tytab[TYchar] |= TYFLuns;
105     bool mscoff = model & 1;
106     model &= 32 | 64;
107     if (generatedMain)
108         cfg.flags2 |= CFG2genmain;
109 
110     if (dwarf < 3 || dwarf > 5)
111     {
112         if (dwarf)
113         {
114             import dmd.backend.errors;
115             error(null, 0, 0, "DWARF version %u is not supported", dwarf);
116         }
117 
118         // Default DWARF version
119         cfg.dwarf = 3;
120     }
121     else
122     {
123         cfg.dwarf = dwarf;
124     }
125 
126     if (cfg.exe & EX_windos)
127     {
128         if (model == 64)
129         {
130             cfg.fpxmmregs = true;
131             cfg.avx = avx;
132             cfg.ehmethod = useExceptions ? EHmethod.EH_DM : EHmethod.EH_NONE;
133 
134             cfg.flags |= CFGnoebp;       // test suite fails without this
135             //cfg.flags |= CFGalwaysframe;
136             cfg.flags |= CFGromable; // put switch tables in code segment
137             cfg.objfmt = OBJ_MSCOFF;
138         }
139         else
140         {
141             cfg.ehmethod = useExceptions ? EHmethod.EH_WIN32 : EHmethod.EH_NONE;
142             if (mscoff)
143                 cfg.flags |= CFGnoebp;       // test suite fails without this
144             cfg.objfmt = mscoff ? OBJ_MSCOFF : OBJ_OMF;
145             if (mscoff)
146                 cfg.flags |= CFGnoebp;    // test suite fails without this
147         }
148 
149         if (exe)
150             cfg.wflags |= WFexe;         // EXE file only optimizations
151         cfg.flags4 |= CFG4underscore;
152     }
153     if (cfg.exe & (EX_LINUX | EX_LINUX64))
154     {
155         cfg.fpxmmregs = true;
156         cfg.avx = avx;
157         if (model == 64)
158         {
159             cfg.ehmethod = useExceptions ? EHmethod.EH_DWARF : EHmethod.EH_NONE;
160         }
161         else
162         {
163             cfg.ehmethod = useExceptions ? EHmethod.EH_DWARF : EHmethod.EH_NONE;
164             if (!exe)
165                 cfg.flags |= CFGromable; // put switch tables in code segment
166         }
167         cfg.flags |= CFGnoebp;
168         switch (pic)
169         {
170             case 0:         // PIC.fixed
171                 break;
172 
173             case 1:         // PIC.pic
174                 cfg.flags3 |= CFG3pic;
175                 break;
176 
177             case 2:         // PIC.pie
178                 cfg.flags3 |= CFG3pic | CFG3pie;
179                 break;
180 
181             default:
182                 assert(0);
183         }
184         if (symdebug)
185             cfg.flags |= CFGalwaysframe;
186 
187         cfg.objfmt = OBJ_ELF;
188     }
189     if (cfg.exe & (EX_OSX | EX_OSX64))
190     {
191         cfg.fpxmmregs = true;
192         cfg.avx = avx;
193         cfg.ehmethod = useExceptions ? EHmethod.EH_DWARF : EHmethod.EH_NONE;
194         cfg.flags |= CFGnoebp;
195         if (!exe)
196         {
197             cfg.flags3 |= CFG3pic;
198             if (model == 64)
199                 cfg.flags |= CFGalwaysframe; // autotester fails without this
200                                                 // https://issues.dlang.org/show_bug.cgi?id=21042
201         }
202         if (symdebug)
203             cfg.flags |= CFGalwaysframe;
204         cfg.flags |= CFGromable; // put switch tables in code segment
205         cfg.objfmt = OBJ_MACH;
206     }
207     if (cfg.exe & (EX_FREEBSD | EX_FREEBSD64))
208     {
209         if (model == 64)
210         {
211             cfg.ehmethod = useExceptions ? EHmethod.EH_DWARF : EHmethod.EH_NONE;
212             cfg.fpxmmregs = true;
213             cfg.avx = avx;
214         }
215         else
216         {
217             cfg.ehmethod = useExceptions ? EHmethod.EH_DWARF : EHmethod.EH_NONE;
218             if (!exe)
219                 cfg.flags |= CFGromable; // put switch tables in code segment
220         }
221         cfg.flags |= CFGnoebp;
222         if (!exe)
223         {
224             cfg.flags3 |= CFG3pic;
225         }
226         if (symdebug)
227             cfg.flags |= CFGalwaysframe;
228         cfg.objfmt = OBJ_ELF;
229     }
230     if (cfg.exe & (EX_OPENBSD | EX_OPENBSD64))
231     {
232         if (model == 64)
233         {
234             cfg.fpxmmregs = true;
235             cfg.avx = avx;
236         }
237         else
238         {
239             if (!exe)
240                 cfg.flags |= CFGromable; // put switch tables in code segment
241         }
242         cfg.flags |= CFGnoebp;
243         cfg.flags |= CFGalwaysframe;
244         if (!exe)
245             cfg.flags3 |= CFG3pic;
246         cfg.objfmt = OBJ_ELF;
247         cfg.ehmethod = useExceptions ? EHmethod.EH_DWARF : EHmethod.EH_NONE;
248     }
249     if (cfg.exe == EX_DRAGONFLYBSD64)
250     {
251         if (model == 64)
252         {
253             cfg.ehmethod = useExceptions ? EHmethod.EH_DWARF : EHmethod.EH_NONE;
254             cfg.fpxmmregs = true;
255             cfg.avx = avx;
256         }
257         else
258         {
259             assert(0);                      // Only 64-bit supported on DragonFlyBSD
260         }
261         cfg.flags |= CFGnoebp;
262         if (!exe)
263         {
264             cfg.flags3 |= CFG3pic;
265             cfg.flags |= CFGalwaysframe; // PIC needs a frame for TLS fixups
266         }
267         cfg.objfmt = OBJ_ELF;
268     }
269     if (cfg.exe & (EX_SOLARIS | EX_SOLARIS64))
270     {
271         if (model == 64)
272         {
273             cfg.fpxmmregs = true;
274             cfg.avx = avx;
275         }
276         else
277         {
278             if (!exe)
279                 cfg.flags |= CFGromable; // put switch tables in code segment
280         }
281         cfg.flags |= CFGnoebp;
282         cfg.flags |= CFGalwaysframe;
283         if (!exe)
284             cfg.flags3 |= CFG3pic;
285         cfg.objfmt = OBJ_ELF;
286         cfg.ehmethod = useExceptions ? EHmethod.EH_DWARF : EHmethod.EH_NONE;
287     }
288 
289     cfg.flags2 |= CFG2nodeflib;      // no default library
290     cfg.flags3 |= CFG3eseqds;
291 static if (0)
292 {
293     if (env.getEEcontext().EEcompile != 2)
294         cfg.flags4 |= CFG4allcomdat;
295     if (env.nochecks())
296         cfg.flags4 |= CFG4nochecks;  // no runtime checking
297 }
298     if (cfg.exe & (EX_OSX | EX_OSX64))
299     {
300     }
301     else
302     {
303         cfg.flags4 |= CFG4allcomdat;
304     }
305     if (trace)
306         cfg.flags |= CFGtrace;       // turn on profiler
307     if (nofloat)
308         cfg.flags3 |= CFG3wkfloat;
309 
310     configv.vasm = vasm;
311     configv.verbose = verbose;
312 
313     if (optimize)
314         go_flag(cast(char*)"-o".ptr);
315 
316     if (symdebug)
317     {
318         if (cfg.exe & (EX_LINUX | EX_LINUX64 | EX_OPENBSD | EX_OPENBSD64 | EX_FREEBSD | EX_FREEBSD64 | EX_DRAGONFLYBSD64 |
319                           EX_SOLARIS | EX_SOLARIS64 | EX_OSX | EX_OSX64))
320         {
321             configv.addlinenumbers = 1;
322             cfg.fulltypes = (symdebug == 1) ? CVDWARF_D : CVDWARF_C;
323         }
324         if (cfg.exe & (EX_windos))
325         {
326             if (cfg.objfmt == OBJ_MSCOFF)
327             {
328                 configv.addlinenumbers = 1;
329                 cfg.fulltypes = CV8;
330                 if(symdebug > 1)
331                     cfg.flags2 |= CFG2gms;
332             }
333             else
334             {
335                 configv.addlinenumbers = 1;
336                 cfg.fulltypes = CV4;
337             }
338         }
339         if (!optimize)
340             cfg.flags |= CFGalwaysframe;
341     }
342     else
343     {
344         configv.addlinenumbers = 0;
345         cfg.fulltypes = CVNONE;
346         //cfg.flags &= ~CFGalwaysframe;
347     }
348 
349     if (alwaysframe)
350         cfg.flags |= CFGalwaysframe;
351     if (stackstomp)
352         cfg.flags2 |= CFG2stomp;
353 
354     cfg.useModuleInfo = useModuleInfo;
355     cfg.useTypeInfo = useTypeInfo;
356     cfg.useExceptions = useExceptions;
357 
358     ph_init();
359     block_init();
360 
361     cod3_setdefault();
362     if (model == 64)
363     {
364         util_set64(cfg.exe);
365         type_init();
366         cod3_set64();
367     }
368     else
369     {
370         util_set32(cfg.exe);
371         type_init();
372         cod3_set32();
373     }
374 
375     if (cfg.objfmt == OBJ_MACH)
376         machDebugSectionsInit();
377     else if (cfg.objfmt == OBJ_ELF)
378         elfDebugSectionsInit();
379     rtlsym_init(); // uses fregsaved, so must be after it's set inside cod3_set*
380 }
381 }
382 
383 /****************************
384  * Transmit internal compiler debugging flags.
385  */
386 @trusted
387 void out_config_debug(
388         bool b,
389         bool c,
390         bool f,
391         bool r,
392         bool w,
393         bool x,
394         bool y
395     )
396 {
397     debugb = b;
398     debugc = c;
399     debugf = f;
400     debugr = r;
401     debugw = w;
402     debugx = x;
403     debugy = y;
404 }
405 
406 /*************************************
407  */
408 
409 @trusted
410 void util_set16()
411 {
412     // The default is 16 bits
413     _tysize[TYldouble] = 10;
414     _tysize[TYildouble] = 10;
415     _tysize[TYcldouble] = 20;
416 
417     _tyalignsize[TYldouble] = 2;
418     _tyalignsize[TYildouble] = 2;
419     _tyalignsize[TYcldouble] = 2;
420 }
421 
422 /*******************************
423  * Redo tables from 8086/286 to 386/486.
424  */
425 
426 @trusted
427 void util_set32(exefmt_t exe)
428 {
429     _tyrelax[TYenum] = TYlong;
430     _tyrelax[TYint]  = TYlong;
431     _tyrelax[TYuint] = TYlong;
432 
433     tyequiv[TYint] = TYlong;
434     tyequiv[TYuint] = TYulong;
435 
436     _tysize[TYenum] = LONGSIZE;
437     _tysize[TYint ] = LONGSIZE;
438     _tysize[TYuint] = LONGSIZE;
439     _tysize[TYnullptr] = LONGSIZE;
440     _tysize[TYnptr] = LONGSIZE;
441     _tysize[TYnref] = LONGSIZE;
442 if (exe & (EX_LINUX | EX_LINUX64 | EX_FREEBSD | EX_FREEBSD64 | EX_OPENBSD | EX_OPENBSD64 | EX_DRAGONFLYBSD64 | EX_SOLARIS | EX_SOLARIS64))
443 {
444     _tysize[TYldouble] = 12;
445     _tysize[TYildouble] = 12;
446     _tysize[TYcldouble] = 24;
447 }
448 if (exe & (EX_OSX | EX_OSX64))
449 {
450     _tysize[TYldouble] = 16;
451     _tysize[TYildouble] = 16;
452     _tysize[TYcldouble] = 32;
453 }
454 if (exe & EX_windos)
455 {
456     _tysize[TYldouble] = 10;
457     _tysize[TYildouble] = 10;
458     _tysize[TYcldouble] = 20;
459 }
460 
461     _tysize[TYsptr] = LONGSIZE;
462     _tysize[TYcptr] = LONGSIZE;
463     _tysize[TYfptr] = 6;     // NOTE: There are codgen test that check
464     _tysize[TYvptr] = 6;     // _tysize[x] == _tysize[TYfptr] so don't set
465     _tysize[TYfref] = 6;     // _tysize[TYfptr] to _tysize[TYnptr]
466 
467     _tyalignsize[TYenum] = LONGSIZE;
468     _tyalignsize[TYint ] = LONGSIZE;
469     _tyalignsize[TYuint] = LONGSIZE;
470     _tyalignsize[TYnullptr] = LONGSIZE;
471     _tyalignsize[TYnref] = LONGSIZE;
472     _tyalignsize[TYnptr] = LONGSIZE;
473 if (exe & (EX_LINUX | EX_LINUX64 | EX_FREEBSD | EX_FREEBSD64 | EX_OPENBSD | EX_OPENBSD64 | EX_DRAGONFLYBSD64 | EX_SOLARIS | EX_SOLARIS64))
474 {
475     _tyalignsize[TYldouble] = 4;
476     _tyalignsize[TYildouble] = 4;
477     _tyalignsize[TYcldouble] = 4;
478 }
479 else if (exe & (EX_OSX | EX_OSX64))
480 {
481     _tyalignsize[TYldouble] = 16;
482     _tyalignsize[TYildouble] = 16;
483     _tyalignsize[TYcldouble] = 16;
484 }
485 if (exe & EX_windos)
486 {
487     _tyalignsize[TYldouble] = 2;
488     _tyalignsize[TYildouble] = 2;
489     _tyalignsize[TYcldouble] = 2;
490 }
491 
492     _tyalignsize[TYsptr] = LONGSIZE;
493     _tyalignsize[TYcptr] = LONGSIZE;
494     _tyalignsize[TYfptr] = LONGSIZE;     // NOTE: There are codgen test that check
495     _tyalignsize[TYvptr] = LONGSIZE;     // _tysize[x] == _tysize[TYfptr] so don't set
496     _tyalignsize[TYfref] = LONGSIZE;     // _tysize[TYfptr] to _tysize[TYnptr]
497 
498     _tysize[TYimmutPtr] = _tysize[TYnptr];
499     _tysize[TYsharePtr] = _tysize[TYnptr];
500     _tysize[TYrestrictPtr] = _tysize[TYnptr];
501     _tysize[TYfgPtr] = _tysize[TYnptr];
502     _tyalignsize[TYimmutPtr] = _tyalignsize[TYnptr];
503     _tyalignsize[TYsharePtr] = _tyalignsize[TYnptr];
504     _tyalignsize[TYrestrictPtr] = _tyalignsize[TYnptr];
505     _tyalignsize[TYfgPtr] = _tyalignsize[TYnptr];
506 }
507 
508 /*******************************
509  * Redo tables from 8086/286 to I64.
510  */
511 
512 @trusted
513 void util_set64(exefmt_t exe)
514 {
515     _tyrelax[TYenum] = TYlong;
516     _tyrelax[TYint]  = TYlong;
517     _tyrelax[TYuint] = TYlong;
518 
519     tyequiv[TYint] = TYlong;
520     tyequiv[TYuint] = TYulong;
521 
522     _tysize[TYenum] = LONGSIZE;
523     _tysize[TYint ] = LONGSIZE;
524     _tysize[TYuint] = LONGSIZE;
525     _tysize[TYnullptr] = 8;
526     _tysize[TYnptr] = 8;
527     _tysize[TYnref] = 8;
528     if (exe & (EX_LINUX | EX_LINUX64 | EX_FREEBSD | EX_FREEBSD64 | EX_OPENBSD |
529                       EX_OPENBSD64 | EX_DRAGONFLYBSD64 | EX_SOLARIS | EX_SOLARIS64 | EX_OSX | EX_OSX64))
530     {
531         _tysize[TYldouble] = 16;
532         _tysize[TYildouble] = 16;
533         _tysize[TYcldouble] = 32;
534     }
535     if (exe & EX_windos)
536     {
537         _tysize[TYldouble] = 10;
538         _tysize[TYildouble] = 10;
539         _tysize[TYcldouble] = 20;
540     }
541     _tysize[TYsptr] = 8;
542     _tysize[TYcptr] = 8;
543     _tysize[TYfptr] = 10;    // NOTE: There are codgen test that check
544     _tysize[TYvptr] = 10;    // _tysize[x] == _tysize[TYfptr] so don't set
545     _tysize[TYfref] = 10;    // _tysize[TYfptr] to _tysize[TYnptr]
546 
547     _tyalignsize[TYenum] = LONGSIZE;
548     _tyalignsize[TYint ] = LONGSIZE;
549     _tyalignsize[TYuint] = LONGSIZE;
550     _tyalignsize[TYnullptr] = 8;
551     _tyalignsize[TYnptr] = 8;
552     _tyalignsize[TYnref] = 8;
553     if (exe & (EX_LINUX | EX_LINUX64 | EX_FREEBSD | EX_FREEBSD64 | EX_OPENBSD | EX_OPENBSD64 | EX_DRAGONFLYBSD64 | EX_SOLARIS | EX_SOLARIS64))
554     {
555         _tyalignsize[TYldouble] = 16;
556         _tyalignsize[TYildouble] = 16;
557         _tyalignsize[TYcldouble] = 16;
558     }
559     if (exe & (EX_OSX | EX_OSX64))
560     {
561         _tyalignsize[TYldouble] = 16;
562         _tyalignsize[TYildouble] = 16;
563         _tyalignsize[TYcldouble] = 16;
564     }
565     if (exe & EX_windos)
566     {
567         _tyalignsize[TYldouble] = 2;
568         _tyalignsize[TYildouble] = 2;
569         _tyalignsize[TYcldouble] = 2;
570     }
571     _tyalignsize[TYsptr] = 8;
572     _tyalignsize[TYcptr] = 8;
573     _tyalignsize[TYfptr] = 8;
574     _tyalignsize[TYvptr] = 8;
575     _tyalignsize[TYfref] = 8;
576     tytab[TYjfunc] &= ~TYFLpascal;  // set so caller cleans the stack (as in C)
577 
578     TYptrdiff = TYllong;
579     TYsize = TYullong;
580     TYsize_t = TYullong;
581     TYdelegate = TYcent;
582     TYdarray = TYucent;
583 
584     _tysize[TYimmutPtr] = _tysize[TYnptr];
585     _tysize[TYsharePtr] = _tysize[TYnptr];
586     _tysize[TYrestrictPtr] = _tysize[TYnptr];
587     _tysize[TYfgPtr] = _tysize[TYnptr];
588     _tyalignsize[TYimmutPtr] = _tyalignsize[TYnptr];
589     _tyalignsize[TYsharePtr] = _tyalignsize[TYnptr];
590     _tyalignsize[TYrestrictPtr] = _tyalignsize[TYnptr];
591     _tyalignsize[TYfgPtr] = _tyalignsize[TYnptr];
592 }