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 }