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