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