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 }