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