1 /** 2 * Generate the object file for function declarations and critical sections. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/glue.d, _glue.d) 8 * Documentation: $(LINK https://dlang.org/phobos/dmd_glue.html) 9 * Coverage: $(LINK https://codecov.io/gh/dlang/dmd/src/master/src/dmd/glue.d) 10 */ 11 12 module dmd.glue; 13 14 import core.stdc.stdio; 15 import core.stdc.string; 16 import core.stdc.stdlib; 17 18 import dmd.root.array; 19 import dmd.root.file; 20 import dmd.root.filename; 21 import dmd.common.outbuffer; 22 import dmd.root.rmem; 23 import dmd.root.string; 24 25 import dmd.backend.cdef; 26 import dmd.backend.cc; 27 import dmd.backend.code; 28 import dmd.backend.dt; 29 import dmd.backend.el; 30 import dmd.backend.global; 31 import dmd.backend.obj; 32 import dmd.backend.oper; 33 import dmd.backend.rtlsym; 34 import dmd.backend.symtab; 35 import dmd.backend.ty; 36 import dmd.backend.type; 37 38 import dmd.aggregate; 39 import dmd.arraytypes; 40 import dmd.astenums; 41 import dmd.blockexit; 42 import dmd.dclass; 43 import dmd.declaration; 44 import dmd.dmangle; 45 import dmd.dmdparams; 46 import dmd.dmodule; 47 import dmd.dmsc; 48 import dmd.dstruct; 49 import dmd.dsymbol; 50 import dmd.dtemplate; 51 import dmd.e2ir; 52 import dmd.errors; 53 import dmd.expression; 54 import dmd.func; 55 import dmd.globals; 56 import dmd.identifier; 57 import dmd.id; 58 import dmd.lib; 59 import dmd.location; 60 import dmd.mtype; 61 import dmd.objc_glue; 62 import dmd.s2ir; 63 import dmd.statement; 64 import dmd.target; 65 import dmd.tocsym; 66 import dmd.toctype; 67 import dmd.toir; 68 import dmd.toobj; 69 import dmd.typesem; 70 import dmd.utils; 71 72 alias symbols = Array!(Symbol*); 73 alias toSymbol = dmd.tocsym.toSymbol; 74 75 /** 76 * Generate code for `modules` and write objects/libraries 77 * 78 * Params: 79 * modules = array of `Module`s to generate code for 80 * libmodules = array of objects/libraries already generated (passed on command line) 81 * libname = {.lib,.a} file output name 82 * objdir = directory to write object files to 83 * lib = write library file instead of object file(s) 84 * obj = generate object files 85 * oneobj = write one object file instead of multiple ones 86 * multiobj = break one object file into multiple ones 87 * verbose = print progress message when generatig code 88 */ 89 void generateCodeAndWrite(Module[] modules, const(char)*[] libmodules, 90 const(char)[] libname, const(char)[] objdir, 91 bool lib, bool obj, bool oneobj, bool multiobj, 92 bool verbose) 93 { 94 Library library = null; 95 if (lib) 96 { 97 library = Library.factory(); 98 library.setFilename(objdir, libname); 99 // Add input object and input library files to output library 100 foreach (p; libmodules) 101 library.addObject(p.toDString(), null); 102 } 103 104 if (!obj) 105 { 106 } 107 else if (oneobj) 108 { 109 OutBuffer objbuf; 110 Module firstm; // first module we generate code for 111 foreach (m; modules) 112 { 113 if (m.filetype == FileType.dhdr) 114 continue; 115 if (!firstm) 116 { 117 firstm = m; 118 obj_start(objbuf, m.srcfile.toChars()); 119 } 120 if (verbose) 121 message("code %s", m.toChars()); 122 genObjFile(m, false); 123 } 124 if (!global.errors && firstm) 125 { 126 obj_end(objbuf, library, firstm.objfile.toChars()); 127 } 128 } 129 else 130 { 131 OutBuffer objbuf; 132 foreach (m; modules) 133 { 134 if (m.filetype == FileType.dhdr) 135 continue; 136 if (verbose) 137 message("code %s", m.toChars()); 138 obj_start(objbuf, m.srcfile.toChars()); 139 genObjFile(m, multiobj); 140 obj_end(objbuf, library, m.objfile.toChars()); 141 obj_write_deferred(objbuf, library, glue.obj_symbols_towrite); 142 if (global.errors && !lib) 143 m.deleteObjFile(); 144 } 145 } 146 if (lib && !global.errors) 147 library.write(); 148 } 149 150 extern (C++): 151 152 //extern 153 __gshared Symbol* bzeroSymbol; /// common location for immutable zeros 154 155 struct Glue 156 { 157 elem *eictor; 158 Symbol *ictorlocalgot; 159 160 symbols sctors; 161 StaticDtorDeclarations ectorgates; 162 symbols sdtors; 163 symbols stests; 164 165 symbols ssharedctors; 166 SharedStaticDtorDeclarations esharedctorgates; 167 symbols sshareddtors; 168 169 const(char)* lastmname; 170 Dsymbols obj_symbols_towrite; 171 } 172 173 private __gshared Glue glue; 174 175 176 /************************************** 177 * Append s to list of object files to generate later. 178 * Only happens with multiobj. 179 */ 180 181 void obj_append(Dsymbol s) 182 { 183 //printf("deferred: %s\n", s.toChars()); 184 glue.obj_symbols_towrite.push(s); 185 } 186 187 /******************************* 188 * Generating multiple object files, one per Dsymbol 189 * in symbols_towrite[]. 190 * Params: 191 * library = library to write object files to 192 * symbols_towrite = array of Dsymbols 193 */ 194 extern (D) 195 private void obj_write_deferred(ref OutBuffer objbuf, Library library, ref Dsymbols symbols_towrite) 196 { 197 // this array can grow during the loop; do not replace with foreach 198 for (size_t i = 0; i < symbols_towrite.length; ++i) 199 { 200 Dsymbol s = symbols_towrite[i]; 201 Module m = s.getModule(); 202 203 const(char)* mname; 204 if (m) 205 { 206 mname = m.srcfile.toChars(); 207 glue.lastmname = mname; 208 } 209 else 210 { 211 //mname = s.ident.toChars(); 212 mname = glue.lastmname; 213 assert(mname); 214 } 215 216 obj_start(objbuf, mname); 217 218 __gshared int count; 219 count++; // sequence for generating names 220 221 /* Create a module that's a doppelganger of m, with just 222 * enough to be able to create the moduleinfo. 223 */ 224 OutBuffer idbuf; 225 idbuf.printf("%s.%d", m ? m.ident.toChars() : mname, count); 226 227 if (!m) 228 { 229 // it doesn't make sense to make up a module if we don't know where to put the symbol 230 // so output it into its own object file without ModuleInfo 231 objmod.initfile(idbuf.peekChars(), null, mname); 232 toObjFile(s, false); 233 objmod.termfile(); 234 } 235 else 236 { 237 Identifier id = Identifier.create(idbuf.extractChars()); 238 239 Module md = new Module(mname.toDString, id, 0, 0); 240 md.members = new Dsymbols(); 241 md.members.push(s); // its only 'member' is s 242 md.doppelganger = 1; // identify this module as doppelganger 243 md.md = m.md; 244 md.aimports.push(m); // it only 'imports' m 245 246 genObjFile(md, false); 247 } 248 249 /* Set object file name to be source name with sequence number, 250 * as mangled symbol names get way too long. 251 */ 252 const(char)* fname = FileName.removeExt(mname); 253 OutBuffer namebuf; 254 uint hash = 0; 255 for (const(char)* p = s.toChars(); *p; p++) 256 hash += *p; 257 namebuf.printf("%s_%x_%x.%.*s", fname, count, hash, 258 cast(int)target.obj_ext.length, target.obj_ext.ptr); 259 FileName.free(cast(char *)fname); 260 fname = namebuf.extractChars(); 261 262 //printf("writing '%s'\n", fname); 263 obj_end(objbuf, library, fname); 264 } 265 glue.obj_symbols_towrite.length = 0; 266 } 267 268 269 /*********************************************** 270 * Generate function that calls array of functions and gates. 271 * Params: 272 * m = module symbol (for name mangling purposes) 273 * sctors = array of functions 274 * ectorgates = array of gates 275 * id = identifier string for generator function 276 * Returns: 277 * function Symbol generated 278 */ 279 280 extern (D) 281 private Symbol *callFuncsAndGates(Module m, Symbol*[] sctors, StaticDtorDeclaration[] ectorgates, 282 const(char)* id) 283 { 284 if (!sctors.length && !ectorgates.length) 285 return null; 286 287 Symbol *sctor = null; 288 289 __gshared type *t; 290 if (!t) 291 { 292 /* t will be the type of the functions generated: 293 * extern (C) void func(); 294 */ 295 t = type_function(TYnfunc, null, false, tstypes[TYvoid]); 296 t.Tmangle = mTYman_c; 297 } 298 299 localgot = null; 300 sctor = toSymbolX(m, id, SC.global, t, "FZv"); 301 cstate.CSpsymtab = &sctor.Sfunc.Flocsym; 302 elem *ector = null; 303 304 foreach (f; ectorgates) 305 { 306 Symbol *s = toSymbol(f.vgate); 307 elem *e = el_var(s); 308 e = el_bin(OPaddass, TYint, e, el_long(TYint, 1)); 309 ector = el_combine(ector, e); 310 } 311 312 foreach (s; sctors) 313 { 314 elem *e = el_una(OPucall, TYvoid, el_var(s)); 315 ector = el_combine(ector, e); 316 } 317 318 block *b = block_calloc(); 319 b.BC = BCret; 320 b.Belem = ector; 321 sctor.Sfunc.Fstartline.Sfilename = m.arg.xarraydup.ptr; 322 sctor.Sfunc.Fstartblock = b; 323 writefunc(sctor); // hand off to backend 324 325 return sctor; 326 } 327 328 /************************************** 329 * Prepare for generating obj file. 330 * Params: 331 * objbuf = write object file contents to this 332 * srcfile = name of the source file 333 */ 334 335 private void obj_start(ref OutBuffer objbuf, const(char)* srcfile) 336 { 337 //printf("obj_start()\n"); 338 339 bzeroSymbol = null; 340 rtlsym_reset(); 341 clearStringTab(); 342 343 version (Windows) 344 { 345 // Produce Ms COFF files by default, OMF for -m32omf 346 assert(objbuf.length() == 0); 347 switch (target.objectFormat()) 348 { 349 case Target.ObjectFormat.coff: objmod = MsCoffObj_init(&objbuf, srcfile, null); break; 350 case Target.ObjectFormat.omf: objmod = OmfObj_init(&objbuf, srcfile, null); break; 351 default: assert(0); 352 } 353 } 354 else 355 { 356 objmod = Obj.initialize(&objbuf, srcfile, null); 357 } 358 359 el_reset(); 360 cg87_reset(); 361 out_reset(); 362 objc.reset(); 363 } 364 365 366 /**************************************** 367 * Finish creating the object module and writing it to objbuf[]. 368 * Then either write the object module to an actual file, 369 * or add it to a library. 370 * Params: 371 * objbuf = contains the generated contents of the object file 372 * objfilename = what to call the object module 373 * library = if non-null, add object module to this library 374 */ 375 private void obj_end(ref OutBuffer objbuf, Library library, const(char)* objfilename) 376 { 377 objmod.term(objfilename); 378 //delete objmod; 379 objmod = null; 380 381 if (library) 382 { 383 // Transfer ownership of image buffer to library 384 library.addObject(objfilename.toDString(), cast(ubyte[]) objbuf.extractSlice[]); 385 } 386 else 387 { 388 //printf("write obj %s\n", objfilename); 389 writeFile(Loc.initial, objfilename.toDString, objbuf[]); 390 391 // For non-libraries, the object buffer should be cleared to 392 // avoid repetitions. 393 objbuf.destroy(); 394 } 395 } 396 397 bool obj_includelib(const(char)* name) nothrow 398 { 399 return objmod.includelib(name); 400 } 401 402 extern(D) bool obj_includelib(const(char)[] name) nothrow 403 { 404 return name.toCStringThen!(n => obj_includelib(n.ptr)); 405 } 406 407 void obj_startaddress(Symbol *s) 408 { 409 return objmod.startaddress(s); 410 } 411 412 bool obj_linkerdirective(const(char)* directive) 413 { 414 return objmod.linkerdirective(directive); 415 } 416 417 418 /************************************** 419 * Generate .obj file for Module. 420 */ 421 422 private void genObjFile(Module m, bool multiobj) 423 { 424 //EEcontext *ee = env.getEEcontext(); 425 426 //printf("Module.genobjfile(multiobj = %d) %s\n", multiobj, m.toChars()); 427 428 glue.lastmname = m.srcfile.toChars(); 429 430 objmod.initfile(glue.lastmname, null, m.toPrettyChars()); 431 432 glue.eictor = null; 433 glue.ictorlocalgot = null; 434 glue.sctors.setDim(0); 435 glue.ectorgates.setDim(0); 436 glue.sdtors.setDim(0); 437 glue.ssharedctors.setDim(0); 438 glue.esharedctorgates.setDim(0); 439 glue.sshareddtors.setDim(0); 440 glue.stests.setDim(0); 441 442 if (m.doppelganger) 443 { 444 /* Generate a reference to the moduleinfo, so the module constructors 445 * and destructors get linked in. 446 */ 447 Module mod = m.aimports[0]; 448 assert(mod); 449 if (mod.sictor || mod.sctor || mod.sdtor || mod.ssharedctor || mod.sshareddtor) 450 { 451 Symbol *s = toSymbol(mod); 452 //objextern(s); 453 //if (!s.Sxtrnnum) objextdef(s.Sident); 454 if (!s.Sxtrnnum) 455 { 456 //printf("%s\n", s.Sident); 457 //#if 0 /* This should work, but causes optlink to fail in common/newlib.asm */ 458 // objextdef(s.Sident); 459 //#else 460 Symbol *sref = symbol_generate(SC.static_, type_fake(TYnptr)); 461 sref.Sfl = FLdata; 462 auto dtb = DtBuilder(0); 463 dtb.xoff(s, 0, TYnptr); 464 sref.Sdt = dtb.finish(); 465 outdata(sref); 466 //#endif 467 } 468 } 469 } 470 471 if (global.params.cov) 472 { 473 /* Create coverage identifier: 474 * uint[numlines] __coverage; 475 */ 476 m.cov = toSymbolX(m, "__coverage", SC.static_, type_fake(TYint), "Z"); 477 m.cov.Sflags |= SFLhidden; 478 m.cov.Stype.Tmangle = mTYman_d; 479 m.cov.Sfl = FLdata; 480 481 auto dtb = DtBuilder(0); 482 483 if (m.ctfe_cov) 484 { 485 // initalize the uint[] __coverage symbol with data from ctfe. 486 static extern (C) int comp_uints (const scope void* a, const scope void* b) 487 { return (*cast(uint*) a) - (*cast(uint*) b); } 488 489 uint[] sorted_lines = m.ctfe_cov.keys; 490 qsort(sorted_lines.ptr, sorted_lines.length, sorted_lines[0].sizeof, 491 &comp_uints); 492 493 uint lastLine = 0; 494 foreach (line;sorted_lines) 495 { 496 // zero fill from last line to line. 497 if (line) 498 { 499 assert(line > lastLine); 500 dtb.nzeros((line - lastLine - 1) * 4); 501 } 502 dtb.dword(m.ctfe_cov[line]); 503 lastLine = line; 504 } 505 // zero fill from last line to end 506 if (m.numlines > lastLine) 507 dtb.nzeros((m.numlines - lastLine) * 4); 508 } 509 else 510 { 511 dtb.nzeros(4 * m.numlines); 512 } 513 m.cov.Sdt = dtb.finish(); 514 515 outdata(m.cov); 516 517 m.covb = cast(uint *)Mem.check(calloc((m.numlines + 32) / 32, (*m.covb).sizeof)); 518 } 519 520 for (int i = 0; i < m.members.length; i++) 521 { 522 auto member = (*m.members)[i]; 523 //printf("toObjFile %s %s\n", member.kind(), member.toChars()); 524 toObjFile(member, multiobj); 525 } 526 527 if (global.params.cov) 528 { 529 /* Generate 530 * private bit[numlines] __bcoverage; 531 */ 532 Symbol *bcov = symbol_calloc("__bcoverage"); 533 bcov.Stype = type_fake(TYuint); 534 bcov.Stype.Tcount++; 535 bcov.Sclass = SC.static_; 536 bcov.Sfl = FLdata; 537 538 auto dtb = DtBuilder(0); 539 dtb.nbytes((m.numlines + 32) / 32 * (*m.covb).sizeof, cast(char *)m.covb); 540 bcov.Sdt = dtb.finish(); 541 542 outdata(bcov); 543 544 free(m.covb); 545 m.covb = null; 546 547 /* Generate: 548 * _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename); 549 * and prepend it to the static constructor. 550 */ 551 552 /* t will be the type of the functions generated: 553 * extern (C) void func(); 554 */ 555 type *t = type_function(TYnfunc, null, false, tstypes[TYvoid]); 556 t.Tmangle = mTYman_c; 557 558 m.sictor = toSymbolX(m, "__modictor", SC.global, t, "FZv"); 559 cstate.CSpsymtab = &m.sictor.Sfunc.Flocsym; 560 localgot = glue.ictorlocalgot; 561 562 elem *ecov = el_pair(TYdarray, el_long(TYsize_t, m.numlines), el_ptr(m.cov)); 563 elem *ebcov = el_pair(TYdarray, el_long(TYsize_t, m.numlines), el_ptr(bcov)); 564 565 if (target.os == Target.OS.Windows && target.is64bit) 566 { 567 ecov = addressElem(ecov, Type.tvoid.arrayOf(), false); 568 ebcov = addressElem(ebcov, Type.tvoid.arrayOf(), false); 569 } 570 571 elem *efilename = toEfilename(m); 572 if (target.os == Target.OS.Windows && target.is64bit) 573 efilename = addressElem(efilename, Type.tstring, true); 574 575 elem *e = el_params( 576 el_long(TYuchar, global.params.covPercent), 577 ecov, 578 ebcov, 579 efilename, 580 null); 581 e = el_bin(OPcall, TYvoid, el_var(getRtlsym(RTLSYM.DCOVER2)), e); 582 glue.eictor = el_combine(e, glue.eictor); 583 glue.ictorlocalgot = localgot; 584 } 585 586 // If coverage / static constructor / destructor / unittest calls 587 if (glue.eictor || glue.sctors.length || glue.ectorgates.length || glue.sdtors.length || 588 glue.ssharedctors.length || glue.esharedctorgates.length || glue.sshareddtors.length || glue.stests.length) 589 { 590 if (glue.eictor) 591 { 592 localgot = glue.ictorlocalgot; 593 594 block *b = block_calloc(); 595 b.BC = BCret; 596 b.Belem = glue.eictor; 597 m.sictor.Sfunc.Fstartline.Sfilename = m.arg.xarraydup.ptr; 598 m.sictor.Sfunc.Fstartblock = b; 599 writefunc(m.sictor); 600 } 601 602 m.sctor = callFuncsAndGates(m, glue.sctors[], glue.ectorgates[], "__modctor"); 603 m.sdtor = callFuncsAndGates(m, glue.sdtors[], null, "__moddtor"); 604 605 m.ssharedctor = callFuncsAndGates(m, glue.ssharedctors[], cast(StaticDtorDeclaration[])glue.esharedctorgates[], "__modsharedctor"); 606 m.sshareddtor = callFuncsAndGates(m, glue.sshareddtors[], null, "__modshareddtor"); 607 m.stest = callFuncsAndGates(m, glue.stests[], null, "__modtest"); 608 609 if (m.doppelganger) 610 genModuleInfo(m); 611 } 612 613 if (m.doppelganger) 614 { 615 objc.generateModuleInfo(m); 616 objmod.termfile(); 617 return; 618 } 619 620 /* Generate module info for templates and -cov. 621 * Don't generate ModuleInfo if `object.ModuleInfo` is not declared or 622 * explicitly disabled through compiler switches such as `-betterC`. 623 * Don't generate ModuleInfo for C files. 624 */ 625 if (global.params.useModuleInfo && Module.moduleinfo && m.filetype != FileType.c/*|| needModuleInfo()*/) 626 genModuleInfo(m); 627 628 objmod.termfile(); 629 } 630 631 632 633 /* ================================================================== */ 634 635 private UnitTestDeclaration needsDeferredNested(FuncDeclaration fd) 636 { 637 while (fd && fd.isNested()) 638 { 639 FuncDeclaration fdp = fd.toParent2().isFuncDeclaration(); 640 if (!fdp) 641 break; 642 if (UnitTestDeclaration udp = fdp.isUnitTestDeclaration()) 643 return udp.semanticRun < PASS.obj ? udp : null; 644 fd = fdp; 645 } 646 return null; 647 } 648 649 650 void FuncDeclaration_toObjFile(FuncDeclaration fd, bool multiobj) 651 { 652 ClassDeclaration cd = fd.parent.isClassDeclaration(); 653 //printf("FuncDeclaration_toObjFile(%p, %s.%s)\n", fd, fd.parent.toChars(), fd.toChars()); 654 //printf("storage_class: %llx\n", fd.storage_class); 655 656 //if (type) printf("type = %s\n", type.toChars()); 657 version (none) 658 { 659 //printf("line = %d\n", getWhere() / LINEINC); 660 EEcontext *ee = env.getEEcontext(); 661 if (ee.EEcompile == 2) 662 { 663 if (ee.EElinnum < (getWhere() / LINEINC) || 664 ee.EElinnum > (endwhere / LINEINC) 665 ) 666 return; // don't compile this function 667 ee.EEfunc = toSymbol(this); 668 } 669 } 670 671 if (fd.semanticRun >= PASS.obj) // if toObjFile() already run 672 return; 673 674 if (fd.type && fd.type.ty == Tfunction && (cast(TypeFunction)fd.type).next is null) 675 return; 676 677 // If errors occurred compiling it, such as https://issues.dlang.org/show_bug.cgi?id=6118 678 if (fd.type && fd.type.ty == Tfunction && (cast(TypeFunction)fd.type).next.ty == Terror) 679 return; 680 681 if (fd.hasSemantic3Errors) 682 return; 683 684 if (global.errors) 685 return; 686 687 if (!fd.fbody) 688 return; 689 690 if (fd.skipCodegen) 691 return; 692 693 UnitTestDeclaration ud = fd.isUnitTestDeclaration(); 694 if (ud && !global.params.useUnitTests) 695 return; 696 697 if (multiobj && !fd.isStaticDtorDeclaration() && !fd.isStaticCtorDeclaration() 698 && !(fd.isCrtCtor || fd.isCrtDtor)) 699 { 700 obj_append(fd); 701 return; 702 } 703 704 if (fd.semanticRun == PASS.semanticdone) 705 { 706 /* What happened is this function failed semantic3() with errors, 707 * but the errors were gagged. 708 * Try to reproduce those errors, and then fail. 709 */ 710 fd.error("errors compiling the function"); 711 return; 712 } 713 assert(fd.semanticRun == PASS.semantic3done); 714 assert(fd.ident != Id.empty); 715 716 for (FuncDeclaration fd2 = fd; fd2; ) 717 { 718 if (fd2.inNonRoot()) 719 return; 720 if (fd2.isNested()) 721 fd2 = fd2.toParent2().isFuncDeclaration(); 722 else 723 break; 724 } 725 726 if (UnitTestDeclaration udp = needsDeferredNested(fd)) 727 { 728 /* Can't do unittest's out of order, they are order dependent in that their 729 * execution is done in lexical order. 730 */ 731 udp.deferredNested.push(fd); 732 //printf("%s @[%s]\n\t-. pushed to unittest @[%s]\n", 733 // fd.toPrettyChars(), fd.loc.toChars(), udp.loc.toChars()); 734 return; 735 } 736 737 // start code generation 738 fd.semanticRun = PASS.obj; 739 740 if (global.params.verbose) 741 message("function %s", fd.toPrettyChars()); 742 743 Symbol *s = toSymbol(fd); 744 func_t *f = s.Sfunc; 745 746 // tunnel type of "this" to debug info generation 747 if (AggregateDeclaration ad = fd.parent.isAggregateDeclaration()) 748 { 749 .type* t = Type_toCtype(ad.getType()); 750 if (cd) 751 t = t.Tnext; // skip reference 752 f.Fclass = cast(Classsym *)t; 753 } 754 755 /* This is done so that the 'this' pointer on the stack is the same 756 * distance away from the function parameters, so that an overriding 757 * function can call the nested fdensure or fdrequire of its overridden function 758 * and the stack offsets are the same. 759 */ 760 if (fd.isVirtual() && (fd.fensure || fd.frequire)) 761 f.Fflags3 |= Ffakeeh; 762 763 if (fd.hasNoEH()) 764 // Same as config.ehmethod==EH_NONE, but only for this function 765 f.Fflags3 |= Feh_none; 766 767 s.Sclass = target.os == Target.OS.OSX ? SC.comdat : SC.global; 768 769 /* Make C static functions SCstatic 770 */ 771 if (fd.storage_class & STC.static_ && fd.isCsymbol()) 772 s.Sclass = SC.static_; 773 774 for (Dsymbol p = fd.parent; p; p = p.parent) 775 { 776 if (p.isTemplateInstance()) 777 { 778 // functions without D or C++ name mangling mixed in at global scope 779 // shouldn't have multiple definitions 780 const linkage = fd.resolvedLinkage(); 781 if (p.isTemplateMixin() && (linkage == LINK.c || linkage == LINK.windows || 782 linkage == LINK.objc)) 783 { 784 const q = p.toParent(); 785 if (q && q.isModule()) 786 { 787 s.Sclass = SC.global; 788 break; 789 } 790 } 791 s.Sclass = SC.comdat; 792 break; 793 } 794 } 795 796 if (fd.inlinedNestedCallees) 797 { 798 /* https://issues.dlang.org/show_bug.cgi?id=15333 799 * If fd contains inlined expressions that come from 800 * nested function bodies, the enclosing of the functions must be 801 * generated first, in order to calculate correct frame pointer offset. 802 */ 803 foreach (fdc; *fd.inlinedNestedCallees) 804 { 805 FuncDeclaration fp = fdc.toParent2().isFuncDeclaration(); 806 if (fp && fp.semanticRun < PASS.obj) 807 { 808 toObjFile(fp, multiobj); 809 } 810 } 811 } 812 813 if (fd.isNested()) 814 { 815 //if (!(config.flags3 & CFG3pic)) 816 // s.Sclass = SCstatic; 817 f.Fflags3 |= Fnested; 818 819 /* The enclosing function must have its code generated first, 820 * in order to calculate correct frame pointer offset. 821 */ 822 FuncDeclaration fdp = fd.toParent2().isFuncDeclaration(); 823 if (fdp && fdp.semanticRun < PASS.obj) 824 { 825 toObjFile(fdp, multiobj); 826 } 827 } 828 else 829 { 830 specialFunctions(objmod, fd); 831 } 832 833 symtab_t *symtabsave = cstate.CSpsymtab; 834 cstate.CSpsymtab = &f.Flocsym; 835 836 // Find module m for this function 837 Module m = null; 838 for (Dsymbol p = fd.parent; p; p = p.parent) 839 { 840 m = p.isModule(); 841 if (m) 842 break; 843 } 844 845 Dsymbols deferToObj; // write these to OBJ file later 846 Array!(elem*) varsInScope; 847 Label*[void*] labels = null; 848 IRState irs = IRState(m, fd, &varsInScope, &deferToObj, &labels, &global.params, &target); 849 850 Symbol *shidden = null; 851 Symbol *sthis = null; 852 tym_t tyf = tybasic(s.Stype.Tty); 853 //printf("linkage = %d, tyf = x%x\n", linkage, tyf); 854 int reverse = tyrevfunc(s.Stype.Tty); 855 856 assert(fd.type.ty == Tfunction); 857 TypeFunction tf = cast(TypeFunction)fd.type; 858 RET retmethod = retStyle(tf, fd.needThis()); 859 if (retmethod == RET.stack) 860 { 861 // If function returns a struct, put a pointer to that 862 // as the first argument 863 .type *thidden = Type_toCtype(tf.next.pointerTo()); 864 const hiddenparamLen = 5 + 10 + 1; 865 char[hiddenparamLen] hiddenparam = void; 866 __gshared uint hiddenparami; // how many we've generated so far 867 868 const(char)* name; 869 if (fd.isNRVO() && fd.nrvo_var) 870 name = fd.nrvo_var.ident.toChars(); 871 else 872 { 873 snprintf(hiddenparam.ptr, hiddenparamLen, "__HID%u", ++hiddenparami); 874 name = hiddenparam.ptr; 875 } 876 shidden = symbol_name(name[0 .. strlen(name)], SC.parameter, thidden); 877 shidden.Sflags |= SFLtrue | SFLfree; 878 if (fd.isNRVO() && fd.nrvo_var && fd.nrvo_var.nestedrefs.length) 879 type_setcv(&shidden.Stype, shidden.Stype.Tty | mTYvolatile); 880 irs.shidden = shidden; 881 fd.shidden = shidden; 882 } 883 else 884 { 885 // Register return style cannot make nrvo. 886 // Auto functions keep the NRVO flag up to here, 887 // so we should eliminate it before entering backend. 888 fd.isNRVO = false; 889 } 890 891 if (fd.vthis) 892 { 893 assert(!fd.vthis.csym); 894 sthis = toSymbol(fd.vthis); 895 sthis.Stype = getParentClosureType(sthis, fd); 896 irs.sthis = sthis; 897 if (!(f.Fflags3 & Fnested)) 898 f.Fflags3 |= Fmember; 899 } 900 901 // Estimate number of parameters, pi 902 size_t pi = (fd.v_arguments !is null); 903 if (fd.parameters) 904 pi += fd.parameters.length; 905 if (fd.objc.selector) 906 pi++; // Extra argument for Objective-C selector 907 // Create a temporary buffer, params[], to hold function parameters 908 Symbol*[10] paramsbuf = void; 909 Symbol **params = paramsbuf.ptr; // allocate on stack if possible 910 if (pi + 2 > paramsbuf.length) // allow extra 2 for sthis and shidden 911 { 912 params = cast(Symbol **)Mem.check(malloc((pi + 2) * (Symbol *).sizeof)); 913 } 914 915 // Get the actual number of parameters, pi, and fill in the params[] 916 pi = 0; 917 if (fd.v_arguments) 918 { 919 params[pi] = toSymbol(fd.v_arguments); 920 pi += 1; 921 } 922 if (fd.parameters) 923 { 924 foreach (i, v; *fd.parameters) 925 { 926 //printf("param[%d] = %p, %s\n", i, v, v.toChars()); 927 assert(!v.csym); 928 params[pi + i] = toSymbol(v); 929 } 930 pi += fd.parameters.length; 931 } 932 933 if (reverse) 934 { 935 // Reverse params[] entries 936 foreach (i, sptmp; params[0 .. pi/2]) 937 { 938 params[i] = params[pi - 1 - i]; 939 params[pi - 1 - i] = sptmp; 940 } 941 } 942 943 if (shidden) 944 { 945 // shidden becomes last parameter 946 //params[pi] = shidden; 947 948 // shidden becomes first parameter 949 memmove(params + 1, params, pi * (params[0]).sizeof); 950 params[0] = shidden; 951 952 pi++; 953 } 954 955 pi = objc.addSelectorParameterSymbol(fd, params, pi); 956 957 if (sthis) 958 { 959 // sthis becomes last parameter 960 //params[pi] = sthis; 961 962 // sthis becomes first parameter 963 memmove(params + 1, params, pi * (params[0]).sizeof); 964 params[0] = sthis; 965 966 pi++; 967 } 968 969 if (target.isPOSIX && fd._linkage != LINK.d && shidden && sthis) 970 { 971 /* swap shidden and sthis 972 */ 973 Symbol *sp = params[0]; 974 params[0] = params[1]; 975 params[1] = sp; 976 } 977 978 foreach (sp; params[0 .. pi]) 979 { 980 sp.Sclass = SC.parameter; 981 sp.Sflags &= ~SFLspill; 982 sp.Sfl = FLpara; 983 symbol_add(sp); 984 } 985 986 // Determine register assignments 987 if (pi) 988 { 989 FuncParamRegs fpr = FuncParamRegs.create(tyf); 990 991 foreach (sp; params[0 .. pi]) 992 { 993 if (fpr.alloc(sp.Stype, sp.Stype.Tty, &sp.Spreg, &sp.Spreg2)) 994 { 995 sp.Sclass = (target.os == Target.OS.Windows && target.is64bit) ? SC.shadowreg : SC.fastpar; 996 sp.Sfl = (sp.Sclass == SC.shadowreg) ? FLpara : FLfast; 997 } 998 } 999 } 1000 1001 // Done with params 1002 if (params != paramsbuf.ptr) 1003 free(params); 1004 params = null; 1005 1006 localgot = null; 1007 1008 Statement sbody = fd.fbody; 1009 1010 Blockx bx; 1011 bx.startblock = block_calloc(); 1012 bx.curblock = bx.startblock; 1013 bx.funcsym = s; 1014 bx.scope_index = -1; 1015 bx.classdec = cast(void*)cd; 1016 bx.member = cast(void*)fd; 1017 bx._module = cast(void*)fd.getModule(); 1018 irs.blx = &bx; 1019 1020 // Initialize argptr 1021 if (fd.v_argptr) 1022 { 1023 // Declare va_argsave 1024 if (target.is64bit && 1025 target.os & Target.OS.Posix) 1026 { 1027 type *t = type_struct_class("__va_argsave_t", 16, 8 * 6 + 8 * 16 + 8 * 3, null, null, false, false, true, false); 1028 // The backend will pick this up by name 1029 Symbol *sv = symbol_name("__va_argsave", SC.auto_, t); 1030 sv.Stype.Tty |= mTYvolatile; 1031 symbol_add(sv); 1032 } 1033 1034 // Declare _argptr, but only for D files 1035 if (!irs.Cfile) 1036 { 1037 Symbol *sa = toSymbol(fd.v_argptr); 1038 symbol_add(sa); 1039 elem *e = el_una(OPva_start, TYnptr, el_ptr(sa)); 1040 block_appendexp(irs.blx.curblock, e); 1041 } 1042 } 1043 1044 /* Doing this in semantic3() caused all kinds of problems: 1045 * 1. couldn't reliably get the final mangling of the function name due to fwd refs 1046 * 2. impact on function inlining 1047 * 3. what to do when writing out .di files, or other pretty printing 1048 */ 1049 if (global.params.trace && !fd.isCMain() && !fd.isNaked() && !(fd.hasReturnExp & 8)) 1050 { 1051 /* The profiler requires TLS, and TLS may not be set up yet when C main() 1052 * gets control (i.e. OSX), leading to a crash. 1053 */ 1054 /* Wrap the entire function body in: 1055 * trace_pro("funcname"); 1056 * try 1057 * body; 1058 * finally 1059 * _c_trace_epi(); 1060 */ 1061 StringExp se = StringExp.create(Loc.initial, s.Sident.ptr); 1062 se.type = Type.tstring; 1063 se.type = se.type.typeSemantic(Loc.initial, null); 1064 Expressions *exps = new Expressions(); 1065 exps.push(se); 1066 FuncDeclaration fdpro = FuncDeclaration.genCfunc(null, Type.tvoid, "trace_pro"); 1067 Expression ec = VarExp.create(Loc.initial, fdpro); 1068 Expression e = CallExp.create(Loc.initial, ec, exps); 1069 e.type = Type.tvoid; 1070 Statement sp = ExpStatement.create(fd.loc, e); 1071 1072 FuncDeclaration fdepi = FuncDeclaration.genCfunc(null, Type.tvoid, "_c_trace_epi"); 1073 ec = VarExp.create(Loc.initial, fdepi); 1074 e = CallExp.create(Loc.initial, ec); 1075 e.type = Type.tvoid; 1076 Statement sf = ExpStatement.create(fd.loc, e); 1077 1078 Statement stf; 1079 if (sbody.blockExit(fd, false) == BE.fallthru) 1080 stf = CompoundStatement.create(Loc.initial, sbody, sf); 1081 else 1082 stf = TryFinallyStatement.create(Loc.initial, sbody, sf); 1083 sbody = CompoundStatement.create(Loc.initial, sp, stf); 1084 } 1085 1086 if (fd.interfaceVirtual) 1087 { 1088 // Adjust the 'this' pointer instead of using a thunk 1089 assert(irs.sthis); 1090 elem *ethis = el_var(irs.sthis); 1091 ethis = fixEthis2(ethis, fd); 1092 elem *e = el_bin(OPminass, TYnptr, ethis, el_long(TYsize_t, fd.interfaceVirtual.offset)); 1093 block_appendexp(irs.blx.curblock, e); 1094 } 1095 1096 buildClosure(fd, &irs); 1097 buildAlignSection(fd, irs); // must be after buildClosure 1098 1099 if (config.ehmethod == EHmethod.EH_WIN32 && fd.isSynchronized() && cd && 1100 !fd.isStatic() && !sbody.usesEH() && !global.params.trace) 1101 { 1102 /* The "jmonitor" hack uses an optimized exception handling frame 1103 * which is a little shorter than the more general EH frame. 1104 */ 1105 s.Sfunc.Fflags3 |= Fjmonitor; 1106 } 1107 1108 Statement_toIR(sbody, &irs); 1109 1110 if (global.errors) 1111 { 1112 // Restore symbol table 1113 cstate.CSpsymtab = symtabsave; 1114 return; 1115 } 1116 1117 bx.curblock.BC = BCret; 1118 1119 f.Fstartblock = bx.startblock; 1120 // einit = el_combine(einit,bx.init); 1121 1122 if (fd.isCtorDeclaration()) 1123 { 1124 assert(sthis); 1125 foreach (b; BlockRange(f.Fstartblock)) 1126 { 1127 if (b.BC == BCret) 1128 { 1129 elem *ethis = el_var(sthis); 1130 ethis = fixEthis2(ethis, fd); 1131 b.BC = BCretexp; 1132 b.Belem = el_combine(b.Belem, ethis); 1133 } 1134 } 1135 } 1136 if (config.ehmethod == EHmethod.EH_NONE || f.Fflags3 & Feh_none) 1137 insertFinallyBlockGotos(f.Fstartblock); 1138 else if (config.ehmethod == EHmethod.EH_DWARF) 1139 insertFinallyBlockCalls(f.Fstartblock); 1140 1141 // If static constructor 1142 if (fd.isSharedStaticCtorDeclaration()) // must come first because it derives from StaticCtorDeclaration 1143 { 1144 glue.ssharedctors.push(s); 1145 } 1146 else if (fd.isStaticCtorDeclaration()) 1147 { 1148 glue.sctors.push(s); 1149 } 1150 1151 // If static destructor 1152 if (fd.isSharedStaticDtorDeclaration()) // must come first because it derives from StaticDtorDeclaration 1153 { 1154 SharedStaticDtorDeclaration fs = fd.isSharedStaticDtorDeclaration(); 1155 assert(fs); 1156 if (fs.vgate) 1157 { 1158 /* Increment destructor's vgate at construction time 1159 */ 1160 glue.esharedctorgates.push(fs); 1161 } 1162 1163 glue.sshareddtors.shift(s); 1164 } 1165 else if (fd.isStaticDtorDeclaration()) 1166 { 1167 StaticDtorDeclaration fs = fd.isStaticDtorDeclaration(); 1168 assert(fs); 1169 if (fs.vgate) 1170 { 1171 /* Increment destructor's vgate at construction time 1172 */ 1173 glue.ectorgates.push(fs); 1174 } 1175 1176 glue.sdtors.shift(s); 1177 } 1178 1179 // If unit test 1180 if (ud) 1181 { 1182 glue.stests.push(s); 1183 } 1184 1185 if (global.errors) 1186 { 1187 // Restore symbol table 1188 cstate.CSpsymtab = symtabsave; 1189 return; 1190 } 1191 1192 writefunc(s); // hand off to backend 1193 1194 buildCapture(fd); 1195 1196 // Restore symbol table 1197 cstate.CSpsymtab = symtabsave; 1198 1199 if (fd.isExport()) 1200 objmod.export_symbol(s, cast(uint)Para.offset); 1201 1202 if (fd.isCrtCtor) 1203 objmod.setModuleCtorDtor(s, true); 1204 1205 if (fd.isCrtDtor) 1206 { 1207 //See TargetC.initialize 1208 if(target.c.crtDestructorsSupported) 1209 { 1210 objmod.setModuleCtorDtor(s, false); 1211 } else 1212 { 1213 /* 1214 https://issues.dlang.org/show_bug.cgi?id=22520 1215 1216 Apple radar: https://openradar.appspot.com/FB9733712 1217 1218 Apple deprecated the mechanism used to implement `crt_destructor` 1219 on MacOS Monterey. This works around that by generating a new function 1220 (crt_destructor_thunk_NNN, run as a constructor) which registers 1221 the destructor-to-be using __cxa_atexit() 1222 1223 This workaround may need a further look at when it comes to 1224 shared library support, however there is no bridge for 1225 that spilt milk to flow under yet. 1226 1227 This relies on the Itanium ABI so is portable to any 1228 platform it, if needed. 1229 */ 1230 __gshared uint nthDestructor = 0; 1231 char* buf = cast(char*) Mem.check(calloc(50, 1)); 1232 const ret = snprintf(buf, 100, "_dmd_crt_destructor_thunk.%u", nthDestructor++); 1233 assert(ret >= 0 && ret < 100, "snprintf either failed or overran buffer"); 1234 //Function symbol 1235 auto newConstructor = symbol_calloc(buf[0 .. strlen(buf)]); 1236 //Build type 1237 newConstructor.Stype = type_function(TYnfunc, [], false, type_alloc(TYvoid)); 1238 //Tell it it's supposed to be a C function. Does it do anything? Not sure. 1239 type_setmangle(&newConstructor.Stype, mTYman_c); 1240 symbol_func(newConstructor); 1241 //Global SC for now. 1242 newConstructor.Sclass = SC.static_; 1243 func_t* funcState = newConstructor.Sfunc; 1244 //Init start block 1245 funcState.Fstartblock = block_calloc(); 1246 block* startBlk = funcState.Fstartblock; 1247 //Make that block run __cxa_atexit(&func); 1248 auto atexitSym = getRtlsym(RTLSYM.CXA_ATEXIT); 1249 Symbol* dso_handle = symbol_calloc("__dso_handle"); 1250 dso_handle.Stype = type_fake(TYint); 1251 //Try to get MacOS _ prefix-ism right. 1252 type_setmangle(&dso_handle.Stype, mTYman_c); 1253 dso_handle.Sfl = FLextern; 1254 dso_handle.Sclass = SC.extern_; 1255 dso_handle.Stype.Tcount++; 1256 auto handlePtr = el_ptr(dso_handle); 1257 //Build parameter pack - __cxa_atexit(&func, null, null) 1258 auto paramPack = el_params(handlePtr, el_long(TYnptr, 0), el_ptr(s), null); 1259 auto exec = el_bin(OPcall, TYvoid, el_var(atexitSym), paramPack); 1260 block_appendexp(startBlk, exec); //payload 1261 startBlk.BC = BCgoto; 1262 auto next = block_calloc(); 1263 startBlk.appendSucc(next); 1264 startBlk.Bnext = next; 1265 next.BC = BCret; 1266 //Emit in binary 1267 writefunc(newConstructor); 1268 //Mark as a CONSTRUCTOR because our thunk implements the destructor 1269 objmod.setModuleCtorDtor(newConstructor, true); 1270 } 1271 } 1272 1273 foreach (sd; *irs.deferToObj) 1274 { 1275 toObjFile(sd, false); 1276 } 1277 1278 if (ud) 1279 { 1280 foreach (fdn; ud.deferredNested) 1281 { 1282 toObjFile(fdn, false); 1283 } 1284 } 1285 1286 if (irs.startaddress) 1287 { 1288 //printf("Setting start address\n"); 1289 objmod.startaddress(irs.startaddress); 1290 } 1291 } 1292 1293 1294 /******************************************* 1295 * Detect special functions like `main()` and do special handling for them, 1296 * like special mangling, including libraries, setting the storage class, etc. 1297 * `objmod` and `fd` are updated. 1298 * 1299 * Params: 1300 * objmod = object module 1301 * fd = function symbol 1302 */ 1303 private void specialFunctions(Obj objmod, FuncDeclaration fd) 1304 { 1305 const libname = finalDefaultlibname(); 1306 1307 Symbol* s = fd.toSymbol(); // backend symbol corresponding to fd 1308 1309 // Pull in RTL startup code (but only once) 1310 if (fd.isMain() && onlyOneMain(fd.loc)) 1311 { 1312 final switch (target.objectFormat()) 1313 { 1314 case Target.ObjectFormat.elf: 1315 case Target.ObjectFormat.macho: 1316 objmod.external_def("_main"); 1317 break; 1318 case Target.ObjectFormat.coff: 1319 objmod.external_def("main"); 1320 break; 1321 case Target.ObjectFormat.omf: 1322 objmod.external_def("_main"); 1323 break; 1324 } 1325 if (libname) 1326 obj_includelib(libname); 1327 s.Sclass = SC.global; 1328 return; 1329 } 1330 else if (fd.isRtInit()) 1331 { 1332 final switch (target.objectFormat()) 1333 { 1334 case Target.ObjectFormat.elf: 1335 case Target.ObjectFormat.macho: 1336 case Target.ObjectFormat.coff: 1337 objmod.ehsections(); // initialize exception handling sections 1338 break; 1339 case Target.ObjectFormat.omf: 1340 break; 1341 } 1342 return; 1343 } 1344 void includeWinLibs(bool cmain, const(char)* omflib) 1345 { 1346 if (target.objectFormat() == Target.ObjectFormat.coff) 1347 { 1348 if (!cmain) 1349 objmod.includelib("uuid"); 1350 if (driverParams.mscrtlib.length && driverParams.mscrtlib[0]) 1351 obj_includelib(driverParams.mscrtlib); 1352 objmod.includelib("OLDNAMES"); 1353 } 1354 else if (target.objectFormat() == Target.ObjectFormat.omf) 1355 { 1356 if (cmain) 1357 { 1358 objmod.external_def("__acrtused_con"); // bring in C startup code 1359 objmod.includelib("snn.lib"); // bring in C runtime library 1360 } 1361 else 1362 { 1363 objmod.external_def(omflib); 1364 } 1365 } 1366 } 1367 if (fd.isCMain()) 1368 { 1369 includeWinLibs(true, ""); 1370 s.Sclass = SC.global; 1371 } 1372 else if (target.os == Target.OS.Windows && fd.isWinMain() && onlyOneMain(fd.loc)) 1373 { 1374 includeWinLibs(false, "__acrtused"); 1375 if (libname) 1376 obj_includelib(libname); 1377 s.Sclass = SC.global; 1378 } 1379 1380 // Pull in RTL startup code 1381 else if (target.os == Target.OS.Windows && fd.isDllMain() && onlyOneMain(fd.loc)) 1382 { 1383 includeWinLibs(false, "__acrtused_dll"); 1384 if (libname) 1385 obj_includelib(libname); 1386 s.Sclass = SC.global; 1387 } 1388 } 1389 1390 1391 private bool onlyOneMain(Loc loc) 1392 { 1393 __gshared Loc lastLoc; 1394 __gshared bool hasMain = false; 1395 if (hasMain) 1396 { 1397 const(char)* otherMainNames = ""; 1398 if (target.os == Target.OS.Windows) 1399 otherMainNames = ", `WinMain`, or `DllMain`"; 1400 error(loc, "only one `main`%s allowed. Previously found `main` at %s", 1401 otherMainNames, lastLoc.toChars()); 1402 return false; 1403 } 1404 lastLoc = loc; 1405 hasMain = true; 1406 return true; 1407 } 1408 1409 /* ================================================================== */ 1410 1411 /***************************** 1412 * Return back end type corresponding to D front end type. 1413 */ 1414 1415 tym_t totym(Type tx) 1416 { 1417 tym_t t; 1418 switch (tx.ty) 1419 { 1420 case Tvoid: t = TYvoid; break; 1421 case Tint8: t = TYschar; break; 1422 case Tuns8: t = TYuchar; break; 1423 case Tint16: t = TYshort; break; 1424 case Tuns16: t = TYushort; break; 1425 case Tint32: t = TYint; break; 1426 case Tuns32: t = TYuint; break; 1427 case Tint64: t = TYllong; break; 1428 case Tuns64: t = TYullong; break; 1429 case Tfloat32: t = TYfloat; break; 1430 case Tfloat64: t = TYdouble; break; 1431 case Tfloat80: t = TYldouble; break; 1432 case Timaginary32: t = TYifloat; break; 1433 case Timaginary64: t = TYidouble; break; 1434 case Timaginary80: t = TYildouble; break; 1435 case Tcomplex32: t = TYcfloat; break; 1436 case Tcomplex64: t = TYcdouble; break; 1437 case Tcomplex80: t = TYcldouble; break; 1438 case Tbool: t = TYbool; break; 1439 case Tchar: t = TYchar; break; 1440 case Twchar: t = TYwchar_t; break; 1441 case Tdchar: 1442 t = (driverParams.symdebug == 1 || target.os & Target.OS.Posix) ? TYdchar : TYulong; 1443 break; 1444 1445 case Taarray: t = TYaarray; break; 1446 case Tclass: 1447 case Treference: 1448 case Tpointer: t = TYnptr; break; 1449 case Tdelegate: t = TYdelegate; break; 1450 case Tarray: t = TYdarray; break; 1451 case Tsarray: t = TYstruct; break; 1452 case Tnoreturn: t = TYnoreturn; break; 1453 1454 case Tstruct: 1455 t = TYstruct; 1456 break; 1457 1458 case Tenum: 1459 { 1460 Type tb = tx.toBasetype(); 1461 const id = tx.toDsymbol(null).ident; 1462 if (id == Id.__c_long) 1463 t = tb.ty == Tint32 ? TYlong : TYllong; 1464 else if (id == Id.__c_ulong) 1465 t = tb.ty == Tuns32 ? TYulong : TYullong; 1466 else if (id == Id.__c_long_double) 1467 t = tb.size() == 8 ? TYdouble : TYldouble; 1468 else if (id == Id.__c_complex_float) 1469 t = TYcfloat; 1470 else if (id == Id.__c_complex_double) 1471 t = TYcdouble; 1472 else if (id == Id.__c_complex_real) 1473 t = tb.size() == 16 ? TYcdouble : TYcldouble; 1474 else 1475 t = totym(tb); 1476 break; 1477 } 1478 1479 case Tident: 1480 case Ttypeof: 1481 case Tmixin: 1482 //printf("ty = %d, '%s'\n", tx.ty, tx.toChars()); 1483 error(Loc.initial, "forward reference of `%s`", tx.toChars()); 1484 t = TYint; 1485 break; 1486 1487 case Tnull: 1488 t = TYnptr; 1489 break; 1490 1491 case Tvector: 1492 { 1493 auto tv = cast(TypeVector)tx; 1494 const tb = tv.elementType(); 1495 const s32 = tv.alignsize() == 32; // if 32 byte, 256 bit vector 1496 switch (tb.ty) 1497 { 1498 case Tvoid: 1499 case Tint8: t = s32 ? TYschar32 : TYschar16; break; 1500 case Tuns8: t = s32 ? TYuchar32 : TYuchar16; break; 1501 case Tint16: t = s32 ? TYshort16 : TYshort8; break; 1502 case Tuns16: t = s32 ? TYushort16 : TYushort8; break; 1503 case Tint32: t = s32 ? TYlong8 : TYlong4; break; 1504 case Tuns32: t = s32 ? TYulong8 : TYulong4; break; 1505 case Tint64: t = s32 ? TYllong4 : TYllong2; break; 1506 case Tuns64: t = s32 ? TYullong4 : TYullong2; break; 1507 case Tfloat32: t = s32 ? TYfloat8 : TYfloat4; break; 1508 case Tfloat64: t = s32 ? TYdouble4 : TYdouble2; break; 1509 default: 1510 assert(0); 1511 } 1512 break; 1513 } 1514 1515 case Tfunction: 1516 { 1517 auto tf = cast(TypeFunction)tx; 1518 final switch (tf.linkage) 1519 { 1520 case LINK.windows: 1521 if (target.is64bit) 1522 goto case LINK.c; 1523 t = (tf.parameterList.varargs == VarArg.variadic || 1524 tf.parameterList.varargs == VarArg.KRvariadic) ? TYnfunc : TYnsfunc; 1525 break; 1526 1527 case LINK.c: 1528 case LINK.cpp: 1529 case LINK.objc: 1530 t = TYnfunc; 1531 if (target.os == Target.OS.Windows) 1532 { 1533 } 1534 else if (!target.is64bit && retStyle(tf, false) == RET.stack) 1535 t = TYhfunc; 1536 break; 1537 1538 case LINK.d: 1539 t = (tf.parameterList.varargs == VarArg.variadic) ? TYnfunc : TYjfunc; 1540 break; 1541 1542 case LINK.default_: 1543 case LINK.system: 1544 printf("linkage = %d\n", tf.linkage); 1545 assert(0); 1546 } 1547 if (tf.isnothrow) 1548 t |= mTYnothrow; 1549 return t; 1550 } 1551 default: 1552 //printf("ty = %d, '%s'\n", tx.ty, tx.toChars()); 1553 assert(0); 1554 } 1555 1556 t |= modToTym(tx.mod); // Add modifiers 1557 1558 return t; 1559 } 1560 1561 /************************************** 1562 */ 1563 1564 Symbol *toSymbol(Type t) 1565 { 1566 if (t.ty == Tclass) 1567 { 1568 return toSymbol((cast(TypeClass)t).sym); 1569 } 1570 assert(0); 1571 } 1572 1573 /******************************************* 1574 * Generate readonly symbol that consists of a bunch of zeros. 1575 * Immutable Symbol instances can be mapped over it. 1576 * Only one is generated per object file. 1577 * Returns: 1578 * bzero symbol 1579 */ 1580 Symbol* getBzeroSymbol() 1581 { 1582 Symbol* s = bzeroSymbol; 1583 if (s) 1584 return s; 1585 1586 s = symbol_calloc("__bzeroBytes"); 1587 s.Stype = type_static_array(128, type_fake(TYuchar)); 1588 s.Stype.Tmangle = mTYman_c; 1589 s.Stype.Tcount++; 1590 s.Sclass = SC.global; 1591 s.Sfl = FLdata; 1592 s.Sflags |= SFLnodebug; 1593 s.Salignment = 16; 1594 1595 auto dtb = DtBuilder(0); 1596 dtb.nzeros(128); 1597 s.Sdt = dtb.finish(); 1598 dt2common(&s.Sdt); 1599 1600 outdata(s); 1601 1602 bzeroSymbol = s; 1603 return s; 1604 } 1605 1606 1607 1608 /************************************** 1609 * Generate elem that is a dynamic array slice of the module file name. 1610 */ 1611 1612 private elem *toEfilename(Module m) 1613 { 1614 //printf("toEfilename(%s)\n", m.toChars()); 1615 const(char)* id = m.srcfile.toChars(); 1616 size_t len = strlen(id); 1617 1618 if (!m.sfilename) 1619 { 1620 // Put out as a static array 1621 m.sfilename = toStringSymbol(id, len, 1); 1622 } 1623 1624 // Turn static array into dynamic array 1625 return el_pair(TYdarray, el_long(TYsize_t, len), el_ptr(m.sfilename)); 1626 } 1627 1628 // Used in e2ir.d 1629 elem *toEfilenamePtr(Module m) 1630 { 1631 //printf("toEfilenamePtr(%s)\n", m.toChars()); 1632 const(char)* id = m.srcfile.toChars(); 1633 size_t len = strlen(id); 1634 Symbol* s = toStringSymbol(id, len, 1); 1635 return el_ptr(s); 1636 }