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