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