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 }