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