1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 1984-1995 by Symantec
6  *              Copyright (C) 2000-2021 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/dcgcv.d, backend/dcgcv.d)
10  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/dcgcv.d
11  */
12 
13 module dmd.backend.dcgcv;
14 
15 version (SCPP)
16     version = COMPILE;
17 version (MARS)
18     version = COMPILE;
19 
20 version (COMPILE)
21 {
22 
23 import core.stdc.stdio;
24 import core.stdc.stdlib;
25 import core.stdc.string;
26 
27 import dmd.backend.cc;
28 import dmd.backend.cdef;
29 import dmd.backend.cgcv;
30 import dmd.backend.code;
31 import dmd.backend.code_x86;
32 import dmd.backend.cv4;
33 import dmd.backend.dlist;
34 import dmd.backend.dvec;
35 import dmd.backend.el;
36 import dmd.backend.global;
37 import dmd.backend.mem;
38 import dmd.backend.obj;
39 import dmd.backend.outbuf;
40 import dmd.backend.symtab;
41 import dmd.backend.ty;
42 import dmd.backend.type;
43 
44 import dmd.backend.barray;
45 
46 version (SCPP)
47 {
48     import cpp;
49     import msgs2;
50     import parser;
51 }
52 version (MARS)
53 {
54     import dmd.backend.dvarstats;
55 }
56 
57 extern (C++):
58 
59 nothrow:
60 
61 enum SYMDEB_TDB = false;
62 
63 extern (C) void TOOFFSET(void* p, targ_size_t value)
64 {
65     switch (_tysize[TYnptr])
66     {
67         case 2: *cast(ushort*)p = cast(ushort)value; break;
68         case 4: *cast(uint*)  p = cast(uint)  value; break;
69         case 8: *cast(ulong*) p = cast(ulong) value; break;
70         default:
71             assert(0);
72     }
73 }
74 
75 extern __gshared char* ftdbname;
76 
77 // Convert from SFL visibilities to CV4 protections
78 uint SFLtoATTR(uint sfl) { return 4 - ((sfl & SFLpmask) >> 5); }
79 
80 __gshared
81 {
82 
83 /* Dynamic array of debtyp_t's  */
84 private Barray!(debtyp_t*) debtyp;
85 
86 private vec_t debtypvec;     // vector of used entries
87 enum DEBTYPVECDIM = 16_001;   //8009 //3001     // dimension of debtypvec (should be prime)
88 
89 enum DEBTYPHASHDIM = 1009;
90 private uint[DEBTYPHASHDIM] debtyphash;
91 
92 private Outbuffer *reset_symbuf; // Keep pointers to reset symbols
93 
94 idx_t DEB_NULL() { return cgcv.deb_offset; }        // index of null debug type record
95 
96 /* This limitation is because of 4K page sizes
97  * in optlink/cv/cvhashes.asm
98  */
99 enum CVIDMAX = (0xFF0-20);   // the -20 is picked by trial and error
100 
101 enum LOCATsegrel = 0xC000;
102 
103 /* Unfortunately, the fixup stuff is different for EASY OMF and Microsoft */
104 enum EASY_LCFDoffset  =      (LOCATsegrel | 0x1404);
105 enum EASY_LCFDpointer =      (LOCATsegrel | 0x1800);
106 
107 enum LCFD32offset     =      (LOCATsegrel | 0x2404);
108 enum LCFD32pointer    =      (LOCATsegrel | 0x2C00);
109 enum LCFD16pointer    =      (LOCATsegrel | 0x0C00);
110 
111 version (MARS)
112     extern Cgcv cgcv; // already declared in cgcv.d
113 else
114     Cgcv cgcv;
115 
116 }
117 
118 version (MARS)
119     enum MARS = true;
120 else
121     enum MARS = false;
122 
123 /******************************************
124  * Return number of bytes consumed in OBJ file by a name.
125  */
126 
127 int cv_stringbytes(const(char)* name)
128 {
129     int len = cast(int)strlen(name);
130     if (config.fulltypes == CV8)
131         return len + 1;
132     if (len > CVIDMAX)
133         len = CVIDMAX;
134     return len + ((len > 255) ? 4 : 1);
135 }
136 
137 /******************************************
138  * Stuff a namestring into p.
139  * Returns:
140  *      number of bytes consumed
141  */
142 
143 int cv_namestring(ubyte *p, const(char)* name, int length = -1)
144 {
145     size_t len = (length >= 0) ? length : strlen(name);
146     if (config.fulltypes == CV8)
147     {
148         size_t numBytesWritten = len + ((length < 0) ? 1 : 0);
149         memcpy(p, name, numBytesWritten);
150         if(config.flags2 & CFG2gms)
151         {
152             for(int i = 0; i < len; i++)
153             {
154                 if(p[i] == '.')
155                     p[i] = '@';
156             }
157         }
158         return cast(int)numBytesWritten;
159     }
160     if (len > 255)
161     {   p[0] = 0xFF;
162         p[1] = 0;
163         if (len > CVIDMAX)
164             len = CVIDMAX;
165         TOWORD(p + 2,cast(uint)len);
166         memcpy(p + 4,name,len);
167         len += 4;
168     }
169     else
170     {   p[0] = cast(ubyte)len;
171         memcpy(p + 1,name,len);
172         len++;
173     }
174     return cast(int)len;
175 }
176 
177 /***********************************
178  * Compute debug register number for symbol s.
179  * Returns:
180  *      0..7    byte registers
181  *      8..15   word registers
182  *      16..23  dword registers
183  */
184 
185 private int cv_regnum(Symbol *s)
186 {
187     uint reg = s.Sreglsw;
188     if (s.Sclass == SCpseudo)
189     {
190 version (SCPP)
191         reg = pseudoreg[reg];
192     }
193     else
194     {
195         assert(reg < 8);
196         assert(s.Sfl == FLreg);
197         switch (type_size(s.Stype))
198         {
199             case LONGSIZE:
200             case 3:             reg += 8;
201                                 goto case;
202 
203             case SHORTSIZE:     reg += 8;
204                                 goto case;
205 
206             case CHARSIZE:      break;
207 
208             case LLONGSIZE:
209                 reg += (s.Sregmsw << 8) + (16 << 8) + 16;
210                 if (config.fulltypes == CV4)
211                     reg += (1 << 8);
212                 break;
213 
214             default:
215 static if (0)
216 {
217                 symbol_print(s);
218                 type_print(s.Stype);
219                 printf("size = %d\n",type_size(s.Stype));
220 }
221                 assert(0);
222         }
223     }
224     if (config.fulltypes == CV4)
225         reg++;
226     return reg;
227 }
228 
229 /***********************************
230  * Allocate a debtyp_t.
231  */
232 
233 debtyp_t * debtyp_alloc(uint length)
234 {
235     debtyp_t *d;
236     uint pad = 0;
237 
238     //printf("len = %u, x%x\n", length, length);
239     if (config.fulltypes == CV8)
240     {   // length+2 must lie on 4 byte boundary
241         pad = ((length + 2 + 3) & ~3) - (length + 2);
242         length += pad;
243     }
244 
245     length < 0x10000 || assert(0);
246     const len = debtyp_t.sizeof - (d.data).sizeof + length;
247 debug
248 {
249     d = cast(debtyp_t *) mem_malloc(len /*+ 1*/);
250     memset(d, 0xAA, len);
251 //    (cast(char*)d)[len] = 0x2E;
252 }
253 else
254 {
255     d = cast(debtyp_t *) malloc(debtyp_t.sizeof - (d.data).sizeof + length);
256 }
257     d.length = cast(ushort)length;
258     if (pad)
259     {
260         __gshared const ubyte[3] padx = [0xF3, 0xF2, 0xF1];
261         memcpy(d.data.ptr + length - pad, padx.ptr + 3 - pad, pad);
262     }
263     //printf("debtyp_alloc(%d) = %p\n", length, d);
264     return d;
265 }
266 
267 /***********************************
268  * Free a debtyp_t.
269  */
270 
271 private void debtyp_free(debtyp_t *d)
272 {
273     //printf("debtyp_free(length = %d, %p)\n", d.length, d);
274     //fflush(stdout);
275 debug
276 {
277     assert(d.length < 0x10000);
278     uint len = debtyp_t.sizeof - (d.data).sizeof + d.length;
279 //    assert((cast(char*)d)[len] == 0x2E);
280     memset(d, 0x55, len);
281     mem_free(d);
282 }
283 else
284 {
285     free(d);
286 }
287 }
288 
289 static if (0)
290 {
291 void debtyp_check(debtyp_t *d,int linnum)
292 {   int i;
293     __gshared char c;
294 
295     //printf("linnum = %d\n",linnum);
296     //printf(" length = %d\n",d.length);
297     for (i = 0; i < d.length; i++)
298         c = d.data.ptr[i];
299 }
300 
301 void debtyp_check(debtyp_t* d) { debtyp_check(d,__LINE__); }
302 }
303 else
304 {
305 void debtyp_check(debtyp_t* d) { }
306 }
307 
308 /***********************************
309  * Search for debtyp_t in debtyp[]. If it is there, return the index
310  * of it, and free d. Otherwise, add it.
311  * Returns:
312  *      index in debtyp[]
313  */
314 
315 idx_t cv_debtyp(debtyp_t *d)
316 {
317     ushort length;
318     uint hashi;
319 
320     assert(d);
321     length = d.length;
322     //printf("length = %3d\n",length);
323 static if (SYMDEB_TDB)
324 {
325     if (config.fulltypes == CVTDB)
326     {
327             idx_t result;
328 
329 static if (1)
330 {
331             assert(length);
332             debtyp_check(d);
333             result = tdb_typidx(&d.length);
334 }
335 else
336 {
337             ubyte *buf;
338 
339             // Allocate buffer
340             buf = malloc(6 + length);
341             if (!buf)
342                 err_nomem();                    // out of memory
343 
344             // Fill the buffer
345             TOLONG(buf,cgcv.signature);
346             memcpy(buf + 4,cast(char *)d + uint.sizeof,2 + length);
347 
348 static if (0)
349 {
350 {int i;
351  for (i=0;i<length;i++)
352  printf("%02x ",buf[6+i]);
353  printf("\n");
354 }
355 }
356             result = tdb_typidx(buf,6 + length);
357 }
358             //printf("result = x%x\n",result);
359             debtyp_free(d);
360             return result;
361     }
362 }
363     if (length)
364     {   uint hash;
365 
366         hash = length;
367         if (length >= uint.sizeof)
368         {
369             // Hash consists of the sum of the first 4 bytes with the last 4 bytes
370             union U { ubyte* cp; uint* up; }
371             U un = void;
372             un.cp = d.data.ptr;
373             hash += *un.up;
374             un.cp += length - uint.sizeof;
375             hash += *un.up;
376         }
377         hashi = hash % DEBTYPHASHDIM;
378         hash %= DEBTYPVECDIM;
379 //printf(" hashi = %d", hashi);
380 
381         if (vec_testbit(hash,debtypvec))
382         {
383 //printf(" test");
384             // Threaded list is much faster
385             for (uint u = debtyphash[hashi]; u; u = debtyp[u].prev)
386             //for (uint u = debtyp.length; u--; )
387             {
388                 if (length == debtyp[u].length &&
389                     memcmp(d.data.ptr,debtyp[u].data.ptr,length) == 0)
390                 {   debtyp_free(d);
391 //printf(" match %d\n",u);
392                     return u + cgcv.deb_offset;
393                 }
394             }
395         }
396         else
397             vec_setbit(hash,debtypvec);
398     }
399     else
400         hashi = 1;
401 //printf(" add   %d\n",debtyp.length);
402     d.prev = debtyphash[hashi];
403     debtyphash[hashi] = cast(uint)debtyp.length;
404 
405     /* It's not already in the array, so add it */
406     debtyp.push(d);
407     version (SCPP)
408     {
409         if (debtyp.length >= 0xE000)
410             err_fatal(EM_2manytypes,0xE000);         // too many types
411     }
412 
413     return cast(uint)debtyp.length - 1 + cgcv.deb_offset;
414 }
415 
416 idx_t cv_numdebtypes()
417 {
418     return cast(idx_t)debtyp.length;
419 }
420 
421 /****************************
422  * Store a null record at DEB_NULL.
423  */
424 
425 void cv_init()
426 {   debtyp_t *d;
427 
428     //printf("cv_init()\n");
429 
430     // Initialize statics
431     debtyp.setLength(0);
432     if (!ftdbname)
433         ftdbname = cast(char *)"symc.tdb".ptr;
434 
435     memset(&cgcv,0,cgcv.sizeof);
436     cgcv.sz_idx = 2;
437     cgcv.LCFDoffset = LCFD32offset;
438     cgcv.LCFDpointer = LCFD16pointer;
439 
440     debtypvec = vec_calloc(DEBTYPVECDIM);
441     memset(debtyphash.ptr,0,debtyphash.sizeof);
442 
443     if (reset_symbuf)
444     {
445         Symbol **p = cast(Symbol **)reset_symbuf.buf;
446         const size_t n = reset_symbuf.length() / (Symbol *).sizeof;
447         for (size_t i = 0; i < n; ++i)
448             symbol_reset(p[i]);
449         reset_symbuf.reset();
450     }
451     else
452     {
453         reset_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof);
454         assert(reset_symbuf);
455         reset_symbuf.reserve(10 * (Symbol*).sizeof);
456     }
457 
458     /* Reset for different OBJ file formats     */
459     if (I32 || I64)
460     {
461         // Adjust values in old CV tables for 32 bit ints
462         dttab[TYenum] = dttab[TYlong];
463         dttab[TYint]  = dttab[TYlong];
464         dttab[TYuint] = dttab[TYulong];
465 
466         // Adjust Codeview 4 values for 32 bit ints and 32 bit pointer offsets
467         dttab4[TYenum] = 0x74;
468         dttab4[TYint]  = 0x74;
469         dttab4[TYuint] = 0x75;
470         if (I64)
471         {
472             dttab4[TYptr]  = 0x600;
473             dttab4[TYnptr] = 0x600;
474             dttab4[TYsptr] = 0x600;
475             dttab4[TYimmutPtr] = 0x600;
476             dttab4[TYsharePtr] = 0x600;
477             dttab4[TYrestrictPtr] = 0x600;
478             dttab4[TYfgPtr] = 0x600;
479         }
480         else
481         {
482             dttab4[TYptr]  = 0x400;
483             dttab4[TYsptr] = 0x400;
484             dttab4[TYnptr] = 0x400;
485             dttab4[TYimmutPtr] = 0x400;
486             dttab4[TYsharePtr] = 0x400;
487             dttab4[TYrestrictPtr] = 0x400;
488             dttab4[TYfgPtr] = 0x400;
489         }
490         dttab4[TYcptr] = 0x400;
491         dttab4[TYfptr] = 0x500;
492 
493         if (config.flags & CFGeasyomf)
494         {   cgcv.LCFDoffset  = EASY_LCFDoffset;
495             cgcv.LCFDpointer = EASY_LCFDpointer;
496             assert(config.fulltypes == CVOLD);
497         }
498         else
499             cgcv.LCFDpointer = LCFD32pointer;
500 
501         if (config.exe & EX_flat)
502             cgcv.FD_code = 0x10;
503     }
504 
505     if (config.fulltypes >= CV4)
506     {   int flags;
507         __gshared ushort[5] memmodel = [0,0x100,0x20,0x120,0x120];
508         char[1 + (VERSION).sizeof] version_;
509         ubyte[8 + (version_).sizeof] debsym;
510 
511         // Put out signature indicating CV4 format
512         switch (config.fulltypes)
513         {
514             case CV4:
515                 cgcv.signature = 1;
516                 break;
517 
518             case CV8:
519                 cgcv.signature = 4;
520                 break;
521 
522             default:
523             {   const(char)* x = "1MYS";
524                 cgcv.signature = *cast(int *) x;
525                 break;
526             }
527         }
528 
529         cgcv.deb_offset = 0x1000;
530 
531         if (config.fulltypes == CV8)
532         {   cgcv.sz_idx = 4;
533             return;     // figure out rest later
534         }
535 
536         if (config.fulltypes >= CVSYM)
537         {   cgcv.sz_idx = 4;
538             if (!(config.flags2 & CFG2phgen))
539                 cgcv.deb_offset = 0x80000000;
540         }
541 
542         objmod.write_bytes(SegData[DEBSYM],4,&cgcv.signature);
543 
544         // Allocate an LF_ARGLIST with no arguments
545         if (config.fulltypes == CV4)
546         {   d = debtyp_alloc(4);
547             TOWORD(d.data.ptr,LF_ARGLIST);
548             TOWORD(d.data.ptr + 2,0);
549         }
550         else
551         {   d = debtyp_alloc(6);
552             TOWORD(d.data.ptr,LF_ARGLIST);
553             TOLONG(d.data.ptr + 2,0);
554         }
555 
556         // Put out S_COMPILE record
557         TOWORD(debsym.ptr + 2,S_COMPILE);
558         switch (config.target_cpu)
559         {
560             case TARGET_8086:   debsym[4] = 0;  break;
561             case TARGET_80286:  debsym[4] = 2;  break;
562             case TARGET_80386:  debsym[4] = 3;  break;
563             case TARGET_80486:  debsym[4] = 4;  break;
564 
565             case TARGET_Pentium:
566             case TARGET_PentiumMMX:
567                                 debsym[4] = 5;  break;
568 
569             case TARGET_PentiumPro:
570             case TARGET_PentiumII:
571                                 debsym[4] = 6;  break;
572             default:    assert(0);
573         }
574         debsym[5] = (CPP != 0);         // 0==C, 1==C++
575         flags = (config.inline8087) ? (0<<3) : (1<<3);
576         if (I32)
577             flags |= 0x80;              // 32 bit addresses
578         flags |= memmodel[config.memmodel];
579         TOWORD(debsym.ptr + 6,flags);
580         version_[0] = 'Z';
581         strcpy(version_.ptr + 1,VERSION);
582         cv_namestring(debsym.ptr + 8,version_.ptr);
583         TOWORD(debsym.ptr,6 + (version_).sizeof);
584         objmod.write_bytes(SegData[DEBSYM],8 + (version_).sizeof,debsym.ptr);
585 
586 static if (SYMDEB_TDB)
587 {
588         // Put out S_TDBNAME record
589         if (config.fulltypes == CVTDB)
590         {
591             ubyte[50] buf = void;
592 
593             pstate.STtdbtimestamp = tdb_gettimestamp();
594             size_t len = cv_stringbytes(ftdbname);
595             ubyte *ds = (8 + len <= buf.sizeof) ? buf : cast(ubyte *) malloc(8 + len);
596             assert(ds);
597             TOWORD(ds,6 + len);
598             TOWORD(ds + 2,S_TDBNAME);
599             TOLONG(ds + 4,pstate.STtdbtimestamp);
600             cv_namestring(ds + 8,ftdbname);
601             objmod.write_bytes(SegData[DEBSYM],8 + len,ds);
602             if (ds != buf)
603                 free(ds);
604         }
605 }
606     }
607     else
608     {
609         assert(0);
610     }
611     if (config.fulltypes == CVTDB)
612         cgcv.deb_offset = cv_debtyp(d);
613     else
614         cv_debtyp(d);
615 }
616 
617 /////////////////////////// CodeView 4 ///////////////////////////////
618 
619 /***********************************
620  * Return number of bytes required to store a numeric leaf.
621  */
622 
623 uint cv4_numericbytes(uint value)
624 {   uint u;
625 
626     if (value < 0x8000)
627         u = 2;
628     else if (value < 0x10000)
629         u = 4;
630     else
631         u = 6;
632     return u;
633 }
634 
635 /********************************
636  * Store numeric leaf.
637  * Must use exact same number of bytes as cv4_numericbytes().
638  */
639 
640 void cv4_storenumeric(ubyte *p, uint value)
641 {
642     if (value < 0x8000)
643         TOWORD(p,value);
644     else if (value < 0x10000)
645     {   TOWORD(p,LF_USHORT);
646         p += 2;
647         TOWORD(p,value);
648     }
649     else
650     {   TOWORD(p,LF_ULONG);
651         *cast(targ_ulong *)(p + 2) = cast(uint) value;
652     }
653 }
654 
655 /***********************************
656  * Return number of bytes required to store a signed numeric leaf.
657  * Params:
658  *   value = value to store
659  * Returns:
660  *   number of bytes required for storing value
661  */
662 uint cv4_signednumericbytes(int value)
663 {
664     uint u;
665     if (value >= 0 && value < 0x8000)
666         u = 2;
667     else if (value == cast(short)value)
668         u = 4;
669     else
670         u = 6;
671     return u;
672 }
673 
674 /********************************
675  * Store signed numeric leaf.
676  * Must use exact same number of bytes as cv4_signednumericbytes().
677  * Params:
678  *   p = address where to store value
679  *   value = value to store
680  */
681 void cv4_storesignednumeric(ubyte *p, int value)
682 {
683     if (value >= 0 && value < 0x8000)
684         TOWORD(p, value);
685     else if (value == cast(short)value)
686     {
687         TOWORD(p, LF_SHORT);
688         TOWORD(p + 2, value);
689     }
690     else
691     {
692         TOWORD(p,LF_LONG);
693         TOLONG(p + 2, value);
694     }
695 }
696 
697 /*********************************
698  * Generate a type index for a parameter list.
699  */
700 
701 idx_t cv4_arglist(type *t,uint *pnparam)
702 {   uint u;
703     uint nparam;
704     idx_t paramidx;
705     debtyp_t *d;
706     param_t *p;
707 
708     // Compute nparam, number of parameters
709     nparam = 0;
710     for (p = t.Tparamtypes; p; p = p.Pnext)
711         nparam++;
712     *pnparam = nparam;
713 
714     // Construct an LF_ARGLIST of those parameters
715     if (nparam == 0)
716     {
717         if (config.fulltypes == CV8)
718         {
719             d = debtyp_alloc(2 + 4 + 4);
720             TOWORD(d.data.ptr,LF_ARGLIST_V2);
721             TOLONG(d.data.ptr + 2,1);
722             TOLONG(d.data.ptr + 6,0);
723             paramidx = cv_debtyp(d);
724         }
725         else
726             paramidx = DEB_NULL;
727     }
728     else
729     {
730         switch (config.fulltypes)
731         {
732             case CV8:
733                 d = debtyp_alloc(2 + 4 + nparam * 4);
734                 TOWORD(d.data.ptr,LF_ARGLIST_V2);
735                 TOLONG(d.data.ptr + 2,nparam);
736 
737                 p = t.Tparamtypes;
738                 for (u = 0; u < nparam; u++)
739                 {   TOLONG(d.data.ptr + 6 + u * 4,cv4_typidx(p.Ptype));
740                     p = p.Pnext;
741                 }
742                 break;
743 
744             case CV4:
745                 d = debtyp_alloc(2 + 2 + nparam * 2);
746                 TOWORD(d.data.ptr,LF_ARGLIST);
747                 TOWORD(d.data.ptr + 2,nparam);
748 
749                 p = t.Tparamtypes;
750                 for (u = 0; u < nparam; u++)
751                 {   TOWORD(d.data.ptr + 4 + u * 2,cv4_typidx(p.Ptype));
752                     p = p.Pnext;
753                 }
754                 break;
755 
756             default:
757                 d = debtyp_alloc(2 + 4 + nparam * 4);
758                 TOWORD(d.data.ptr,LF_ARGLIST);
759                 TOLONG(d.data.ptr + 2,nparam);
760 
761                 p = t.Tparamtypes;
762                 for (u = 0; u < nparam; u++)
763                 {   TOLONG(d.data.ptr + 6 + u * 4,cv4_typidx(p.Ptype));
764                     p = p.Pnext;
765                 }
766                 break;
767         }
768         paramidx = cv_debtyp(d);
769     }
770     return paramidx;
771 }
772 
773 /*****************************
774  * Build LF_METHODLIST for overloaded member function.
775  * Output:
776  *      *pcount         # of entries in method list
777  * Returns:
778  *      type index of method list
779  *      0 don't do this one
780  */
781 
782 version (SCPP)
783 {
784 
785 private int cv4_methodlist(Symbol *sf,int *pcount)
786 {   int count;
787     int mlen;
788     Symbol *s;
789     debtyp_t *d;
790     ubyte *p;
791     ushort attribute;
792 
793     symbol_debug(sf);
794 
795     // First, compute how big the method list is
796     count = 0;
797     mlen = 2;
798     for (s = sf; s; s = s.Sfunc.Foversym)
799     {
800         if (s.Sclass == SCtypedef || s.Sclass == SCfunctempl)
801             continue;
802         if (s.Sfunc.Fflags & Fnodebug)
803             continue;
804         if (s.Sfunc.Fflags & Fintro)
805             mlen += 4;
806         mlen += cgcv.sz_idx * 2;
807         count++;
808     }
809 
810     if (!count)
811         return 0;
812 
813     // Allocate and fill it in
814     d = debtyp_alloc(mlen);
815     p = d.data.ptr;
816     TOWORD(p,LF_METHODLIST);
817     p += 2;
818     for (s = sf; s; s = s.Sfunc.Foversym)
819     {
820         if (s.Sclass == SCtypedef || s.Sclass == SCfunctempl)
821             continue;
822         if (s.Sfunc.Fflags & Fnodebug)
823             continue;
824         attribute = cast(ushort)SFLtoATTR(s.Sflags);
825         // Make sure no overlapping bits
826         assert((Fvirtual | Fpure | Fintro | Fstatic) == (Fvirtual ^ Fpure ^ Fintro ^ Fstatic));
827         switch ((s.Sfunc.Fflags & (Fvirtual | Fstatic)) |
828                 (s.Sfunc.Fflags & (Fpure | Fintro)))
829         {
830             // BUG: should we have 0x0C, friend functions?
831             case Fstatic:                       attribute |= 0x08; break;
832             case Fvirtual:                      attribute |= 0x04; break;
833             case Fvirtual | Fintro:             attribute |= 0x10; break;
834             case Fvirtual | Fpure:              attribute |= 0x14; break;
835             case Fvirtual | Fintro | Fpure:     attribute |= 0x18; break;
836 
837             case 0:
838                 break;
839 
840             default:
841                 symbol_print(s);
842                 assert(0);
843         }
844         TOIDX(p,attribute);
845         p += cgcv.sz_idx;
846         TOIDX(p,cv4_symtypidx(s));
847         p += cgcv.sz_idx;
848         if (s.Sfunc.Fflags & Fintro)
849         {   TOLONG(p,cpp_vtbloffset(cast(Classsym *)s.Sscope,s));
850             p += 4;
851         }
852     }
853     assert(p - d.data.ptr == mlen);
854 
855     *pcount = count;
856     return cv_debtyp(d);
857 }
858 
859 }
860 
861 /**********************************
862  * Pretty-print indentifier for CV4 types.
863  */
864 
865 version (SCPP)
866 {
867 
868 private const(char)* cv4_prettyident(Symbol *s)
869 {   Symbol *stmp;
870 
871     stmp = s.Sscope;
872     s.Sscope = null;           // trick cpp_prettyident into leaving off ::
873     const p = cpp_prettyident(s);
874     s.Sscope = cast(Classsym *)stmp;
875     return p;
876 }
877 
878 }
879 
880 /****************************
881  * Return type index of struct.
882  * Input:
883  *      s       struct tag symbol
884  *      flags
885  *          0   generate a reference to s
886  *          1   just saw the definition of s
887  *          2   saw key function for class s
888  *          3   no longer have a key function for class s
889  */
890 
891 idx_t cv4_struct(Classsym *s,int flags)
892 {   targ_size_t size;
893     debtyp_t* d,dt;
894     uint len;
895     uint nfields,fnamelen;
896     idx_t typidx;
897     type *t;
898     struct_t *st;
899     const(char)* id;
900 version (SCPP)
901 {
902     baseclass_t *b;
903 }
904     uint numidx;
905     uint leaf;
906     uint property;
907     uint attribute;
908     ubyte *p;
909     int refonly;
910     int i;
911     int count;                  // COUNT field in LF_CLASS
912 
913     symbol_debug(s);
914     assert(config.fulltypes >= CV4);
915     st = s.Sstruct;
916     if (st.Sflags & STRanonymous)      // if anonymous class/union
917         return 0;
918 
919     //printf("cv4_struct(%s,%d)\n",s.Sident.ptr,flags);
920     t = s.Stype;
921     //printf("t = %p, Tflags = x%x\n", t, t.Tflags);
922     type_debug(t);
923 
924     // Determine if we should do a reference or a definition
925     refonly = 1;                        // assume reference only
926     if (MARS || t.Tflags & TFsizeunknown || st.Sflags & STRoutdef)
927     {
928         //printf("ref only\n");
929     }
930     else
931     {
932         // We have a definition that we have not put out yet
933         switch (flags)
934         {
935             case 0:                     // reference to s
936 version (SCPP)
937 {
938                 if (!CPP ||
939                     config.flags2 & (CFG2fulltypes | CFG2hdrdebug) ||
940                     !(st.Sflags & STRvtblext))
941                     refonly = 0;
942 }
943 else
944 {
945                 refonly = 0;
946 }
947                 break;
948 
949             case 1:                     // saw def of s
950                 if (!s.Stypidx)        // if not forward referenced
951                     return 0;
952 version (SCPP)
953 {
954                 if (!CPP ||
955                     config.flags2 & CFG2fulltypes ||
956                     !(st.Sflags & STRvtblext))
957                     refonly = 0;
958 }
959                 break;
960 
961 version (SCPP)
962 {
963             case 2:                     // saw key func for s
964                 if (config.flags2 & CFG2fulltypes)
965                     return 0;
966                 refonly = 0;
967                 break;
968 
969             case 3:                     // no longer have key func for s
970                 if (!s.Stypidx || config.flags2 & CFG2fulltypes)
971                     return 0;
972                 refonly = 0;
973                 break;
974 }
975             default:
976                 assert(0);
977         }
978     }
979 
980     if (MARS || refonly)
981     {
982         if (s.Stypidx)                 // if reference already generated
983         {   //assert(s.Stypidx - cgcv.deb_offset < debtyp.length);
984             return s.Stypidx;          // use already existing reference
985         }
986         size = 0;
987         property = 0x80;                // class is forward referenced
988     }
989     else
990     {   size = type_size(t);
991         st.Sflags |= STRoutdef;
992         property = 0;
993     }
994 
995 version (SCPP)
996 {
997     if (CPP)
998     {
999         if (s.Sscope)                  // if class is nested
1000             property |= 8;
1001         if (st.Sctor || st.Sdtor)
1002             property |= 2;              // class has ctors and/or dtors
1003         if (st.Sopoverload)
1004             property |= 4;              // class has overloaded operators
1005         if (st.Scastoverload)
1006             property |= 0x40;           // class has casting methods
1007         if (st.Sopeq && !(st.Sopeq.Sfunc.Fflags & Fnodebug))
1008             property |= 0x20;           // class has overloaded assignment
1009     }
1010 }
1011     id = prettyident(s);
1012     if (config.fulltypes == CV4)
1013     {   numidx = (st.Sflags & STRunion) ? 8 : 12;
1014         len = numidx + cv4_numericbytes(cast(uint)size);
1015         d = debtyp_alloc(len + cv_stringbytes(id));
1016         cv4_storenumeric(d.data.ptr + numidx,cast(uint)size);
1017     }
1018     else
1019     {   numidx = (st.Sflags & STRunion) ? 10 : 18;
1020         len = numidx + 4;
1021         d = debtyp_alloc(len + cv_stringbytes(id));
1022         TOLONG(d.data.ptr + numidx,cast(uint)size);
1023     }
1024     len += cv_namestring(d.data.ptr + len,id);
1025     switch (s.Sclass)
1026     {
1027         case SCstruct:
1028             leaf = LF_STRUCTURE;
1029             if (st.Sflags & STRunion)
1030             {   leaf = LF_UNION;
1031                 break;
1032             }
1033             if (st.Sflags & STRclass)
1034                 leaf = LF_CLASS;
1035             goto L1;
1036         L1:
1037             if (config.fulltypes == CV4)
1038                 TOWORD(d.data.ptr + 8,0);          // dList
1039             else
1040                 TOLONG(d.data.ptr + 10,0);         // dList
1041         if (CPP)
1042         {
1043 version (SCPP)
1044 {
1045             debtyp_t *vshape;
1046             ubyte descriptor;
1047 
1048             const n = list_nitems(st.Svirtual);
1049             if (n == 0)                         // if no virtual functions
1050             {
1051                 if (config.fulltypes == CV4)
1052                     TOWORD(d.data.ptr + 10,0);             // vshape is 0
1053                 else
1054                     TOLONG(d.data.ptr + 14,0);             // vshape is 0
1055             }
1056             else
1057             {
1058                 vshape = debtyp_alloc(4 + (n + 1) / 2);
1059                 TOWORD(vshape.data.ptr,LF_VTSHAPE);
1060                 TOWORD(vshape.data.ptr + 2,1);
1061 
1062                 uint n2 = 0;
1063                 descriptor = 0;
1064                 foreach (vl; ListRange(st.Svirtual))
1065                 {   mptr_t *m;
1066                     tym_t ty;
1067 
1068                     m = list_mptr(vl);
1069                     symbol_debug(m.MPf);
1070                     ty = tybasic(m.MPf.ty());
1071                     assert(tyfunc(ty));
1072                     if (_tysize[TYint] == 4)
1073                         descriptor |= 5;
1074                     if (tyfarfunc(ty))
1075                         descriptor++;
1076                     vshape.data.ptr[4 + n2 / 2] = descriptor;
1077                     descriptor <<= 4;
1078                     n2++;
1079                 }
1080                 if (config.fulltypes == CV4)
1081                     TOWORD(d.data.ptr + 10,cv_debtyp(vshape));     // vshape
1082                 else
1083                     TOLONG(d.data.ptr + 14,cv_debtyp(vshape));     // vshape
1084             }
1085 }
1086         }
1087         else
1088         {
1089             if (config.fulltypes == CV4)
1090                 TOWORD(d.data.ptr + 10,0);         // vshape
1091             else
1092                 TOLONG(d.data.ptr + 14,0);         // vshape
1093         }
1094             break;
1095 
1096         default:
1097             symbol_print(s);
1098             assert(0);
1099     }
1100     TOWORD(d.data.ptr,leaf);
1101 
1102     // Assign a number to prevent infinite recursion if a struct member
1103     // references the same struct.
1104     if (config.fulltypes == CVTDB)
1105     {
1106 static if (SYMDEB_TDB)
1107 {
1108         TOWORD(d.data.ptr + 2,0);          // number of fields
1109         TOLONG(d.data.ptr + 6,0);          // field list is 0
1110         TOWORD(d.data.ptr + 4,property | 0x80);    // set fwd ref bit
1111 static if (0)
1112 {
1113 printf("fwd struct ref\n");
1114 {int i;
1115  printf("len = %d, length = %d\n",len,d.length);
1116  for (i=0;i<d.length;i++)
1117  printf("%02x ",d.data.ptr[i]);
1118  printf("\n");
1119 }
1120 }
1121         debtyp_check(d);
1122         s.Stypidx = tdb_typidx(&d.length);    // forward reference it
1123 }
1124     }
1125     else
1126     {
1127         d.length = 0;                  // so cv_debtyp() will allocate new
1128         s.Stypidx = cv_debtyp(d);
1129         d.length = cast(ushort)len;    // restore length
1130     }
1131     reset_symbuf.write((&s)[0 .. 1]);
1132 
1133     if (refonly)                        // if reference only
1134     {
1135         //printf("refonly\n");
1136         TOWORD(d.data.ptr + 2,0);          // count: number of fields is 0
1137         if (config.fulltypes == CV4)
1138         {   TOWORD(d.data.ptr + 4,0);              // field list is 0
1139             TOWORD(d.data.ptr + 6,property);
1140         }
1141         else
1142         {   TOLONG(d.data.ptr + 6,0);              // field list is 0
1143             TOWORD(d.data.ptr + 4,property);
1144         }
1145         return s.Stypidx;
1146     }
1147 
1148 version (MARS)
1149     util_progress();
1150 else
1151     file_progress();
1152 
1153     // Compute the number of fields, and the length of the fieldlist record
1154     nfields = 0;
1155     fnamelen = 2;
1156 version (SCPP)
1157 {
1158     if (CPP)
1159     {
1160     // Base classes come first
1161     for (b = st.Sbase; b; b = b.BCnext)
1162     {
1163         if (b.BCflags & BCFvirtual)    // skip virtual base classes
1164             continue;
1165         nfields++;
1166         fnamelen += ((config.fulltypes == CV4) ? 6 : 8) +
1167                     cv4_numericbytes(b.BCoffset);
1168     }
1169 
1170     // Now virtual base classes (direct and indirect)
1171     for (b = st.Svirtbase; b; b = b.BCnext)
1172     {
1173         nfields++;
1174         fnamelen += ((config.fulltypes == CV4) ? 8 : 12) +
1175                         cv4_numericbytes(st.Svbptr_off) +
1176                         cv4_numericbytes(b.BCvbtbloff / _tysize[TYint]);
1177     }
1178 
1179     // Now friend classes
1180     i = list_nitems(st.Sfriendclass);
1181     nfields += i;
1182     fnamelen += i * ((config.fulltypes == CV4) ? 4 : 8);
1183 
1184     // Now friend functions
1185     foreach (sl; ListRange(st.Sfriendfuncs))
1186     {   Symbol *sf = list_symbol(sl);
1187 
1188         symbol_debug(sf);
1189         if (sf.Sclass == SCfunctempl)
1190             continue;
1191         nfields++;
1192         fnamelen += ((config.fulltypes == CV4) ? 4 : 6) +
1193                     cv_stringbytes(cpp_unmangleident(sf.Sident.ptr));
1194     }
1195     }
1196 }
1197     count = nfields;
1198     foreach (sl; ListRange(st.Sfldlst))
1199     {   Symbol *sf = list_symbol(sl);
1200         targ_size_t offset;
1201 
1202         symbol_debug(sf);
1203         const(char)* sfid = sf.Sident.ptr;
1204         switch (sf.Sclass)
1205         {
1206             case SCmember:
1207             case SCfield:
1208                 if (CPP && sf == s.Sstruct.Svptr)
1209                     fnamelen += ((config.fulltypes == CV4) ? 4 : 8);
1210                 else
1211                 {   offset = sf.Smemoff;
1212                     fnamelen += ((config.fulltypes == CV4) ? 6 : 8) +
1213                                 cv4_numericbytes(cast(uint)offset) + cv_stringbytes(sfid);
1214                 }
1215                 break;
1216 
1217 version (SCPP)
1218 {
1219             case SCstruct:
1220                 if (sf.Sstruct.Sflags & STRanonymous)
1221                     continue;
1222                 if (sf.Sstruct.Sflags & STRnotagname)
1223                     sfid = cpp_name_none.ptr;
1224                 property |= 0x10;       // class contains nested classes
1225                 goto Lnest2;
1226 
1227             case SCenum:
1228                 if (sf.Senum.SEflags & SENnotagname)
1229                     sfid = cpp_name_none.ptr;
1230                 goto Lnest2;
1231 
1232             case SCtypedef:
1233             Lnest2:
1234                 fnamelen += ((config.fulltypes == CV4) ? 4 : 8) +
1235                             cv_stringbytes(sfid);
1236                 break;
1237 
1238             case SCextern:
1239             case SCcomdef:
1240             case SCglobal:
1241             case SCstatic:
1242             case SCinline:
1243             case SCsinline:
1244             case SCeinline:
1245             case SCcomdat:
1246                 if (tyfunc(sf.ty()))
1247                 {   Symbol *so;
1248                     int nfuncs;
1249 
1250                     nfuncs = 0;
1251                     for (so = sf; so; so = so.Sfunc.Foversym)
1252                     {
1253                         if (so.Sclass == SCtypedef ||
1254                             so.Sclass == SCfunctempl ||
1255                             so.Sfunc.Fflags & Fnodebug)       // if compiler generated
1256                             continue;                   // skip it
1257                         nfuncs++;
1258                     }
1259                     if (nfuncs == 0)
1260                         continue;
1261 
1262                     if (nfuncs > 1)
1263                         count += nfuncs - 1;
1264 
1265                     sfid = cv4_prettyident(sf);
1266                 }
1267                 fnamelen += ((config.fulltypes == CV4) ? 6 : 8) +
1268                             cv_stringbytes(sfid);
1269                 break;
1270 }
1271 
1272             default:
1273                 continue;
1274         }
1275         nfields++;
1276         count++;
1277     }
1278 
1279     TOWORD(d.data.ptr + 2,count);
1280     if (config.fulltypes == CV4)
1281         TOWORD(d.data.ptr + 6,property);
1282     else
1283         TOWORD(d.data.ptr + 4,property);
1284 
1285     // Generate fieldlist type record
1286     dt = debtyp_alloc(fnamelen);
1287     p = dt.data.ptr;
1288     TOWORD(p,LF_FIELDLIST);
1289 
1290     // And fill it in
1291     p += 2;
1292 version (SCPP)
1293 {
1294     if (CPP)
1295     {
1296     // Put out real base classes
1297     for (b = st.Sbase; b; b = b.BCnext)
1298     {   targ_size_t offset;
1299 
1300         if (b.BCflags & BCFvirtual)    // skip virtual base classes
1301             continue;
1302         offset = b.BCoffset;
1303         typidx = cv4_symtypidx(b.BCbase);
1304 
1305         attribute = (b.BCflags & BCFpmask);
1306         if (attribute & 4)
1307             attribute = 1;
1308         else
1309             attribute = 4 - attribute;
1310 
1311         TOWORD(p,LF_BCLASS);
1312         if (config.fulltypes == CV4)
1313         {   TOWORD(p + 2,typidx);
1314             TOWORD(p + 4,attribute);
1315             p += 6;
1316         }
1317         else
1318         {   TOLONG(p + 4,typidx);
1319             TOWORD(p + 2,attribute);
1320             p += 8;
1321         }
1322 
1323         cv4_storenumeric(p,offset);
1324         p += cv4_numericbytes(offset);
1325     }
1326 
1327     // Now direct followed by indirect virtual base classes
1328     i = LF_VBCLASS;
1329     do
1330     {
1331         for (b = st.Svirtbase; b; b = b.BCnext)
1332         {   targ_size_t vbpoff,vboff;
1333             type *vbptype;              // type of virtual base pointer
1334             idx_t vbpidx;
1335 
1336             if (baseclass_find(st.Sbase,b.BCbase))    // if direct vbase
1337             {   if (i == LF_IVBCLASS)
1338                     continue;
1339             }
1340             else
1341             {   if (i == LF_VBCLASS)
1342                     continue;
1343             }
1344 
1345             typidx = cv4_symtypidx(b.BCbase);
1346 
1347             vbptype = type_allocn(TYarray,tstypes[TYint]);
1348             vbptype.Tflags |= TFsizeunknown;
1349             vbptype = newpointer(vbptype);
1350             vbptype.Tcount++;
1351             vbpidx = cv4_typidx(vbptype);
1352             type_free(vbptype);
1353 
1354             attribute = (b.BCflags & BCFpmask);
1355             if (attribute & 4)
1356                 attribute = 1;
1357             else
1358                 attribute = 4 - attribute;
1359 
1360             vbpoff = st.Svbptr_off;
1361             vboff = b.BCvbtbloff / _tysize[TYint];
1362 
1363             if (config.fulltypes == CV4)
1364             {   TOWORD(p,i);
1365                 TOWORD(p + 2,typidx);
1366                 TOWORD(p + 4,vbpidx);
1367                 TOWORD(p + 6,attribute);
1368                 p += 8;
1369             }
1370             else
1371             {   TOWORD(p,i);
1372                 TOLONG(p + 4,typidx);           // btype
1373                 TOLONG(p + 8,vbpidx);           // vbtype
1374                 TOWORD(p + 2,attribute);
1375                 p += 12;
1376             }
1377 
1378             cv4_storenumeric(p,vbpoff);
1379             p += cv4_numericbytes(vbpoff);
1380             cv4_storenumeric(p,vboff);
1381             p += cv4_numericbytes(vboff);
1382         }
1383         i ^= LF_VBCLASS ^ LF_IVBCLASS;          // toggle between them
1384     } while (i != LF_VBCLASS);
1385 
1386     // Now friend classes
1387     foreach (sl; ListRange(s.Sstruct.Sfriendclass))
1388     {   Symbol *sf = list_symbol(sl);
1389 
1390         symbol_debug(sf);
1391         typidx = cv4_symtypidx(sf);
1392         if (config.fulltypes == CV4)
1393         {   TOWORD(p,LF_FRIENDCLS);
1394             TOWORD(p + 2,typidx);
1395             p += 4;
1396         }
1397         else
1398         {   TOLONG(p,LF_FRIENDCLS);
1399             TOLONG(p + 4,typidx);
1400             p += 8;
1401         }
1402     }
1403 
1404     // Now friend functions
1405     foreach (sl; ListRange(s.Sstruct.Sfriendfuncs))
1406     {   Symbol *sf = list_symbol(sl);
1407 
1408         symbol_debug(sf);
1409         if (sf.Sclass == SCfunctempl)
1410             continue;
1411         typidx = cv4_symtypidx(sf);
1412         TOWORD(p,LF_FRIENDFCN);
1413         if (config.fulltypes == CV4)
1414         {   TOWORD(p + 2,typidx);
1415             p += 4;
1416         }
1417         else
1418         {   TOLONG(p + 2,typidx);
1419             p += 6;
1420         }
1421         p += cv_namestring(p,cpp_unmangleident(sf.Sident.ptr));
1422     }
1423     }
1424 }
1425     foreach (sl; ListRange(s.Sstruct.Sfldlst))
1426     {   Symbol *sf = list_symbol(sl);
1427         targ_size_t offset;
1428 
1429         symbol_debug(sf);
1430         const(char)* sfid = sf.Sident.ptr;
1431         switch (sf.Sclass)
1432         {
1433             case SCfield:
1434             {   debtyp_t *db;
1435 
1436                 if (config.fulltypes == CV4)
1437                 {   db = debtyp_alloc(6);
1438                     TOWORD(db.data.ptr,LF_BITFIELD);
1439                     db.data.ptr[2] = sf.Swidth;
1440                     db.data.ptr[3] = sf.Sbit;
1441                     TOWORD(db.data.ptr + 4,cv4_symtypidx(sf));
1442                 }
1443                 else
1444                 {   db = debtyp_alloc(8);
1445                     TOWORD(db.data.ptr,LF_BITFIELD);
1446                     db.data.ptr[6] = sf.Swidth;
1447                     db.data.ptr[7] = sf.Sbit;
1448                     TOLONG(db.data.ptr + 2,cv4_symtypidx(sf));
1449                 }
1450                 typidx = cv_debtyp(db);
1451                 goto L3;
1452             }
1453 
1454             case SCmember:
1455                 typidx = cv4_symtypidx(sf);
1456             L3:
1457 version (SCPP)
1458 {
1459                 if (CPP && sf == s.Sstruct.Svptr)
1460                 {
1461                     if (config.fulltypes == CV4)
1462                     {   TOWORD(p,LF_VFUNCTAB);
1463                         TOWORD(p + 2,typidx);
1464                         p += 4;
1465                     }
1466                     else
1467                     {   TOLONG(p,LF_VFUNCTAB);          // 0 fill 2 bytes
1468                         TOLONG(p + 4,typidx);
1469                         p += 8;
1470                     }
1471                     break;
1472                 }
1473 }
1474                 offset = sf.Smemoff;
1475                 TOWORD(p,LF_MEMBER);
1476 version (SCPP)
1477 {
1478                 attribute = CPP ? SFLtoATTR(sf.Sflags) : 0;
1479                 assert((attribute & ~3) == 0);
1480 }
1481 else
1482 {
1483                 attribute = 0;
1484 }
1485                 if (config.fulltypes == CV4)
1486                 {   TOWORD(p + 2,typidx);
1487                     TOWORD(p + 4,attribute);
1488                     p += 6;
1489                 }
1490                 else
1491                 {   TOLONG(p + 4,typidx);
1492                     TOWORD(p + 2,attribute);
1493                     p += 8;
1494                 }
1495                 cv4_storenumeric(p,cast(uint)offset);
1496                 p += cv4_numericbytes(cast(uint)offset);
1497                 p += cv_namestring(p,sfid);
1498                 break;
1499 
1500 version (SCPP)
1501 {
1502             case SCstruct:
1503                 if (sf.Sstruct.Sflags & STRanonymous)
1504                     continue;
1505                 if (sf.Sstruct.Sflags & STRnotagname)
1506                     sfid = cpp_name_none.ptr;
1507                 goto Lnest;
1508 
1509             case SCenum:
1510                 if (sf.Senum.SEflags & SENnotagname)
1511                     sfid = cpp_name_none.ptr;
1512                 goto Lnest;
1513 
1514             case SCtypedef:
1515             Lnest:
1516                 TOWORD(p,LF_NESTTYPE);
1517                 typidx = cv4_symtypidx(sf);
1518                 if (config.fulltypes == CV4)
1519                 {   TOWORD(p + 2,typidx);
1520                     p += 4;
1521                 }
1522                 else
1523                 {   TOLONG(p + 4,typidx);
1524                     p += 8;
1525                 }
1526             L2:
1527                 p += cv_namestring(p,sfid);
1528                 break;
1529 
1530             case SCextern:
1531             case SCcomdef:
1532             case SCglobal:
1533             case SCstatic:
1534             case SCinline:
1535             case SCsinline:
1536             case SCeinline:
1537             case SCcomdat:
1538                 if (tyfunc(sf.ty()))
1539                 {   int count2;
1540 
1541                     typidx = cv4_methodlist(sf,&count2);
1542                     if (!typidx)
1543                         break;
1544                     sfid = cv4_prettyident(sf);
1545                     TOWORD(p,LF_METHOD);
1546                     TOWORD(p + 2,count2);
1547                     p += 4;
1548                     TOIDX(p,typidx);
1549                     p += cgcv.sz_idx;
1550                     goto L2;
1551                 }
1552                 else
1553                 {
1554                     TOWORD(p,LF_STMEMBER);
1555                     typidx = cv4_symtypidx(sf);
1556                     attribute = SFLtoATTR(sf.Sflags);
1557                     if (config.fulltypes == CV4)
1558                     {   TOWORD(p + 2,typidx);
1559                         TOWORD(p + 4,attribute);
1560                         p += 6;
1561                     }
1562                     else
1563                     {   TOLONG(p + 4,typidx);
1564                         TOWORD(p + 2,attribute);
1565                         p += 8;
1566                     }
1567                     goto L2;
1568                 }
1569                 break;
1570 }
1571 
1572             default:
1573                 continue;
1574         }
1575     }
1576     //printf("fnamelen = %d, p-dt.data = %d\n",fnamelen,p-dt.data);
1577     assert(p - dt.data.ptr == fnamelen);
1578     if (config.fulltypes == CV4)
1579         TOWORD(d.data.ptr + 4,cv_debtyp(dt));
1580     else
1581         TOLONG(d.data.ptr + 6,cv_debtyp(dt));
1582 
1583 static if (SYMDEB_TDB)
1584 {
1585     if (config.fulltypes == CVTDB)
1586     {
1587         s.Stypidx = cv_debtyp(d);
1588         reset_symbuf.write(&s, (s).sizeof);
1589     }
1590 }
1591 version (SCPP)
1592 {
1593     if (CPP)
1594     {
1595         symbol_debug(s);
1596         if (st.Sflags & STRglobal)
1597             list_prepend(&cgcv.list,s);
1598         else
1599             cv4_outsym(s);
1600     }
1601 }
1602     return s.Stypidx;
1603 }
1604 
1605 /****************************
1606  * Return type index of enum.
1607  */
1608 
1609 version (SCPP)
1610 {
1611 
1612 private uint cv4_enum(Symbol *s)
1613 {
1614     debtyp_t* d,dt;
1615     uint nfields,fnamelen;
1616     uint len;
1617     type *t;
1618     type *tbase;
1619     uint property;
1620     uint attribute;
1621     int i;
1622     char *id;
1623 
1624     symbol_debug(s);
1625     if (s.Stypidx)                     // if already converted
1626     {   //assert(s.Stypidx - cgcv.deb_offset < debtyp.length);
1627         return s.Stypidx;
1628     }
1629 
1630     //printf("cv4_enum(%s)\n",s.Sident.ptr);
1631     t = s.Stype;
1632     type_debug(t);
1633     tbase = t.Tnext;
1634     property = 0;
1635     if (s.Senum.SEflags & SENforward)
1636         property |= 0x80;               // enum is forward referenced
1637 
1638     id = s.Sident.ptr;
1639     if (s.Senum.SEflags & SENnotagname)
1640         id = cpp_name_none.ptr;
1641     if (config.fulltypes == CV4)
1642     {   len = 10;
1643         d = debtyp_alloc(len + cv_stringbytes(id));
1644         TOWORD(d.data.ptr,LF_ENUM);
1645         TOWORD(d.data.ptr + 4,cv4_typidx(tbase));
1646         TOWORD(d.data.ptr + 8,property);
1647     }
1648     else
1649     {   len = 14;
1650         d = debtyp_alloc(len + cv_stringbytes(id));
1651         TOWORD(d.data.ptr,LF_ENUM);
1652         TOLONG(d.data.ptr + 6,cv4_typidx(tbase));
1653         TOWORD(d.data.ptr + 4,property);
1654     }
1655     len += cv_namestring(d.data.ptr + len,id);
1656 
1657     // Assign a number to prevent infinite recursion if an enum member
1658     // references the same enum.
1659     if (config.fulltypes == CVTDB)
1660     {
1661 static if (SYMDEB_TDB)
1662 {
1663         debtyp_t *df;
1664 
1665         TOWORD(d.data.ptr + 2,0);
1666         TOWORD(d.data.ptr + 6,0);
1667         debtyp_check(d);
1668         s.Stypidx = tdb_typidx(&d.length);    // forward reference it
1669 }
1670     }
1671     else
1672     {
1673         d.length = 0;                  // so cv_debtyp() will allocate new
1674         s.Stypidx = cv_debtyp(d);
1675         d.length = cast(ushort)len;           // restore length
1676     }
1677     reset_symbuf.write((&s)[0 .. 1]);
1678 
1679     // Compute the number of fields, and the length of the fieldlist record
1680     nfields = 0;
1681     fnamelen = 2;
1682     foreach (sl; ListRange(s.Senum.SEenumlist))
1683     {   Symbol *sf = list_symbol(sl);
1684         uint value;
1685 
1686         symbol_debug(sf);
1687         value = cast(uint)el_tolongt(sf.Svalue);
1688         nfields++;
1689         fnamelen += 4 + cv4_numericbytes(value) + cv_stringbytes(sf.Sident.ptr);
1690     }
1691 
1692     TOWORD(d.data.ptr + 2,nfields);
1693 
1694     // If forward reference, then field list is 0
1695     if (s.Senum.SEflags & SENforward)
1696     {
1697         TOWORD(d.data.ptr + 6,0);
1698         return s.Stypidx;
1699     }
1700 
1701     // Generate fieldlist type record
1702     dt = debtyp_alloc(fnamelen);
1703     TOWORD(dt.data.ptr,LF_FIELDLIST);
1704 
1705     // And fill it in
1706     i = 2;
1707     foreach (sl; ListRange(s.Senum.SEenumlist))
1708     {   Symbol *sf = list_symbol(sl);
1709         uint value;
1710 
1711         symbol_debug(sf);
1712         value = cast(uint)el_tolongt(sf.Svalue);
1713         TOWORD(dt.data.ptr + i,LF_ENUMERATE);
1714         attribute = SFLtoATTR(sf.Sflags);
1715         TOWORD(dt.data.ptr + i + 2,attribute);
1716         cv4_storenumeric(dt.data.ptr + i + 4,value);
1717         i += 4 + cv4_numericbytes(value);
1718         i += cv_namestring(dt.data.ptr + i,sf.Sident.ptr);
1719 
1720         // If enum is not a member of a class, output enum members as constants
1721         if (!isclassmember(s))
1722         {   symbol_debug(sf);
1723             cv4_outsym(sf);
1724         }
1725     }
1726     assert(i == fnamelen);
1727     if (config.fulltypes == CV4)
1728         TOWORD(d.data.ptr + 6,cv_debtyp(dt));
1729     else
1730         TOLONG(d.data.ptr + 10,cv_debtyp(dt));
1731 
1732     symbol_debug(s);
1733     if (CPP)
1734         cv4_outsym(s);
1735     return s.Stypidx;
1736 }
1737 
1738 }
1739 else
1740 {
1741 private uint cv4_fwdenum(type* t)
1742 {
1743     Symbol* s = t.Ttag;
1744 
1745     // write a forward reference enum record that is enough for the linker to
1746     // fold with original definition from EnumDeclaration
1747     uint bty = dttab4[tybasic(t.Tnext.Tty)];
1748     const id = prettyident(s);
1749     uint len = config.fulltypes == CV8 ? 14 : 10;
1750     debtyp_t* d = debtyp_alloc(len + cv_stringbytes(id));
1751     switch (config.fulltypes)
1752     {
1753         case CV8:
1754             TOWORD(d.data.ptr, LF_ENUM_V3);
1755             TOLONG(d.data.ptr + 2, 0);    // count
1756             TOWORD(d.data.ptr + 4, 0x80); // property : forward reference
1757             TOLONG(d.data.ptr + 6, bty);  // memtype
1758             TOLONG(d.data.ptr + 10, 0);   // fieldlist
1759             break;
1760 
1761         case CV4:
1762             TOWORD(d.data.ptr,LF_ENUM);
1763             TOWORD(d.data.ptr + 2, 0);    // count
1764             TOWORD(d.data.ptr + 4, bty);  // memtype
1765             TOLONG(d.data.ptr + 6, 0);    // fieldlist
1766             TOWORD(d.data.ptr + 8, 0x80); // property : forward reference
1767             break;
1768 
1769         default:
1770             assert(0);
1771     }
1772     cv_namestring(d.data.ptr + len, id);
1773     s.Stypidx = cv_debtyp(d);
1774     return s.Stypidx;
1775 }
1776 
1777 }
1778 /************************************************
1779  * Return 'calling convention' type of function.
1780  */
1781 
1782 ubyte cv4_callconv(type *t)
1783 {   ubyte call;
1784 
1785     switch (tybasic(t.Tty))
1786     {
1787         case TYffunc:   call = 1;       break;
1788         case TYfpfunc:  call = 3;       break;
1789         case TYf16func: call = 3;       break;
1790         case TYfsfunc:  call = 8;       break;
1791         case TYnsysfunc: call = 9;      break;
1792         case TYfsysfunc: call = 10;     break;
1793         case TYnfunc:   call = 0;       break;
1794         case TYnpfunc:  call = 2;       break;
1795         case TYnsfunc:  call = 7;       break;
1796         case TYifunc:   call = 1;       break;
1797         case TYjfunc:   call = 2;       break;
1798         case TYmfunc:   call = 11;      break;  // this call
1799         default:
1800             assert(0);
1801     }
1802     return call;
1803 }
1804 
1805 /**********************************************
1806  * Return type index for the type of a symbol.
1807  */
1808 
1809 version (MARS)
1810 {
1811 
1812 private uint cv4_symtypidx(Symbol *s)
1813 {
1814     return cv4_typidx(s.Stype);
1815 }
1816 
1817 }
1818 
1819 version (SCPP)
1820 {
1821 
1822 private uint cv4_symtypidx(Symbol *s)
1823 {   type *t;
1824     debtyp_t *d;
1825     ubyte *p;
1826 
1827     if (!CPP)
1828         return cv4_typidx(s.Stype);
1829     symbol_debug(s);
1830     if (isclassmember(s))
1831     {   t = s.Stype;
1832         if (tyfunc(t.Tty))
1833         {   param_t *pa;
1834             uint nparam;
1835             idx_t paramidx;
1836             idx_t thisidx;
1837             uint u;
1838             func_t *f;
1839             ubyte call;
1840 
1841             // It's a member function, which gets a special type record
1842 
1843             f = s.Sfunc;
1844             if (f.Fflags & Fstatic)
1845                 thisidx = dttab4[TYvoid];
1846             else
1847             {   type *tthis = cpp_thistype(s.Stype,cast(Classsym *)s.Sscope);
1848 
1849                 thisidx = cv4_typidx(tthis);
1850                 type_free(tthis);
1851             }
1852 
1853             paramidx = cv4_arglist(t,&nparam);
1854             call = cv4_callconv(t);
1855 
1856             if (config.fulltypes == CV4)
1857             {
1858                 d = debtyp_alloc(18);
1859                 p = d.data.ptr;
1860                 TOWORD(p,LF_MFUNCTION);
1861                 TOWORD(p + 2,cv4_typidx(t.Tnext));
1862                 TOWORD(p + 4,cv4_symtypidx(s.Sscope));
1863                 TOWORD(p + 6,thisidx);
1864                 p[8] = call;
1865                 p[9] = 0;                               // reserved
1866                 TOWORD(p + 10,nparam);
1867                 TOWORD(p + 12,paramidx);
1868                 TOLONG(p + 14,0);                       // thisadjust
1869             }
1870             else
1871             {
1872                 d = debtyp_alloc(26);
1873                 p = d.data.ptr;
1874                 TOWORD(p,LF_MFUNCTION);
1875                 TOLONG(p + 2,cv4_typidx(t.Tnext));
1876                 TOLONG(p + 6,cv4_symtypidx(s.Sscope));
1877                 TOLONG(p + 10,thisidx);
1878                 p[14] = call;
1879                 p[15] = 0;                              // reserved
1880                 TOWORD(p + 16,nparam);
1881                 TOLONG(p + 18,paramidx);
1882                 TOLONG(p + 22,0);                       // thisadjust
1883             }
1884             return cv_debtyp(d);
1885         }
1886     }
1887     return cv4_typidx(s.Stype);
1888 }
1889 
1890 }
1891 
1892 /***********************************
1893  * Return CV4 type index for a type.
1894  */
1895 
1896 uint cv4_typidx(type *t)
1897 {   uint typidx;
1898     uint u;
1899     uint next;
1900     uint key;
1901     debtyp_t *d;
1902     targ_size_t size;
1903     tym_t tym;
1904     tym_t tycv;
1905     tym_t tymnext;
1906     type *tv;
1907     uint dt;
1908     uint attribute;
1909     ubyte call;
1910 
1911     //printf("cv4_typidx(%p)\n",t);
1912     if (!t)
1913         return dttab4[TYint];           // assume int
1914     type_debug(t);
1915     next = cv4_typidx(t.Tnext);
1916     tycv = t.Tty;
1917     tym = tybasic(tycv);
1918     tycv &= mTYconst | mTYvolatile | mTYimmutable;
1919     attribute = 0;
1920 L1:
1921     dt = dttab4[tym];
1922     switch (tym)
1923     {
1924         case TYllong:
1925             if (t.Tnext)
1926                 goto Ldelegate;
1927             assert(dt);
1928             typidx = dt;
1929             break;
1930 
1931         case TYullong:
1932             if (t.Tnext)
1933                 goto Ldarray;
1934             assert(dt);
1935             typidx = dt;
1936             break;
1937 
1938         case TYvoid:
1939         case TYchar:
1940         case TYschar:
1941         case TYuchar:
1942         case TYchar16:
1943         case TYshort:
1944         case TYushort:
1945         case TYint:
1946         case TYuint:
1947         case TYulong:
1948         case TYlong:
1949         case TYfloat:
1950         case TYdouble:
1951         case TYdouble_alias:
1952         case TYldouble:
1953         case TYifloat:
1954         case TYidouble:
1955         case TYildouble:
1956         case TYcfloat:
1957         case TYcdouble:
1958         case TYcldouble:
1959         case TYbool:
1960         case TYwchar_t:
1961         case TYdchar:
1962             assert(dt);
1963             typidx = dt;
1964             break;
1965 
1966         case TYnptr:
1967         case TYimmutPtr:
1968         case TYsharePtr:
1969         case TYrestrictPtr:
1970 version (MARS)
1971 {
1972             if (t.Tkey)
1973                 goto Laarray;
1974 }
1975             goto Lptr;
1976         case TYsptr:
1977         case TYcptr:
1978         case TYfgPtr:
1979         Lptr:
1980                         attribute |= I32 ? 10 : 0;      goto L2;
1981 
1982         case TYfptr:
1983         case TYvptr:    attribute |= I32 ? 11 : 1;      goto L2;
1984         case TYhptr:    attribute |= 2; goto L2;
1985 
1986         L2:
1987             if (config.fulltypes == CV4)
1988             {
1989                 // This is a hack to duplicate bugs in VC, so that the VC
1990                 // debugger will work.
1991                 tymnext = t.Tnext ? t.Tnext.Tty : TYint;
1992                 if (tymnext & (mTYconst | mTYimmutable | mTYvolatile) &&
1993                     !tycv &&
1994                     tyarithmetic(tymnext) &&
1995                     !(attribute & 0xE0)
1996                    )
1997                 {
1998                     typidx = dt | dttab4[tybasic(tymnext)];
1999                     break;
2000                 }
2001             }
2002             if ((next & 0xFF00) == 0 && !(attribute & 0xE0))
2003                 typidx = next | dt;
2004             else
2005             {
2006                 if (tycv & (mTYconst | mTYimmutable))
2007                     attribute |= 0x400;
2008                 if (tycv & mTYvolatile)
2009                     attribute |= 0x200;
2010                 tycv = 0;
2011                 switch (config.fulltypes)
2012                 {
2013                     case CV4:
2014                         d = debtyp_alloc(6);
2015                         TOWORD(d.data.ptr,LF_POINTER);
2016                         TOWORD(d.data.ptr + 2,attribute);
2017                         TOWORD(d.data.ptr + 4,next);
2018                         break;
2019 
2020                     case CV8:
2021                         d = debtyp_alloc(10);
2022                         TOWORD(d.data.ptr,0x1002);
2023                         TOLONG(d.data.ptr + 2,next);
2024                         // see https://github.com/Microsoft/microsoft-pdb/blob/master/include/cvinfo.h#L1514
2025                         // add size and pointer type (PTR_64 or PTR_NEAR32)
2026                         attribute |= (I64 ? (8 << 13) | 0xC : (4 << 13) | 0xA);
2027                         // convert reference to r-value reference to remove & from type display in debugger
2028                         if (attribute & 0x20)
2029                             attribute |= 0x80;
2030                         TOLONG(d.data.ptr + 6,attribute);
2031                         break;
2032 
2033                     default:
2034                         d = debtyp_alloc(10);
2035                         TOWORD(d.data.ptr,LF_POINTER);
2036                         TOLONG(d.data.ptr + 2,attribute);
2037                         TOLONG(d.data.ptr + 6,next);
2038                         break;
2039                 }
2040                 typidx = cv_debtyp(d);
2041             }
2042             break;
2043 
2044         Ldarray:
2045             switch (config.fulltypes)
2046             {
2047 version (MARS)
2048 {
2049                 case CV8:
2050                 {
2051                     typidx = cv8_darray(t, next);
2052                     break;
2053                 }
2054 }
2055                 case CV4:
2056 static if (1)
2057 {
2058                     d = debtyp_alloc(12);
2059                     TOWORD(d.data.ptr, LF_OEM);
2060                     TOWORD(d.data.ptr + 2, OEM);
2061                     TOWORD(d.data.ptr + 4, 1);     // 1 = dynamic array
2062                     TOWORD(d.data.ptr + 6, 2);     // count of type indices to follow
2063                     TOWORD(d.data.ptr + 8, 0x12);  // index type, T_LONG
2064                     TOWORD(d.data.ptr + 10, next); // element type
2065 }
2066 else
2067 {
2068                     d = debtyp_alloc(6);
2069                     TOWORD(d.data.ptr,LF_DYN_ARRAY);
2070                     TOWORD(d.data.ptr + 2, 0x12);  // T_LONG
2071                     TOWORD(d.data.ptr + 4, next);
2072 }
2073                     typidx = cv_debtyp(d);
2074                     break;
2075 
2076                 default:
2077                     assert(0);
2078             }
2079 
2080             break;
2081 
2082         Laarray:
2083 version (MARS)
2084 {
2085             key = cv4_typidx(t.Tkey);
2086             switch (config.fulltypes)
2087             {
2088                 case CV8:
2089                     typidx = cv8_daarray(t, key, next);
2090                     break;
2091 
2092                 case CV4:
2093 static if (1)
2094 {
2095                     d = debtyp_alloc(12);
2096                     TOWORD(d.data.ptr, LF_OEM);
2097                     TOWORD(d.data.ptr + 2, OEM);
2098                     TOWORD(d.data.ptr + 4, 2);     // 2 = associative array
2099                     TOWORD(d.data.ptr + 6, 2);     // count of type indices to follow
2100                     TOWORD(d.data.ptr + 8, key);   // key type
2101                     TOWORD(d.data.ptr + 10, next); // element type
2102 }
2103 else
2104 {
2105                     d = debtyp_alloc(6);
2106                     TOWORD(d.data.ptr,LF_ASSOC_ARRAY);
2107                     TOWORD(d.data.ptr + 2, key);   // key type
2108                     TOWORD(d.data.ptr + 4, next);  // element type
2109 }
2110                     typidx = cv_debtyp(d);
2111                     break;
2112 
2113                 default:
2114                     assert(0);
2115             }
2116 }
2117             break;
2118 
2119         Ldelegate:
2120             switch (config.fulltypes)
2121             {
2122 version (MARS)
2123 {
2124                 case CV8:
2125                     typidx = cv8_ddelegate(t, next);
2126                     break;
2127 }
2128 
2129                 case CV4:
2130                     tv = type_fake(TYnptr);
2131                     tv.Tcount++;
2132                     key = cv4_typidx(tv);
2133                     type_free(tv);
2134 static if (1)
2135 {
2136                     d = debtyp_alloc(12);
2137                     TOWORD(d.data.ptr, LF_OEM);
2138                     TOWORD(d.data.ptr + 2, OEM);
2139                     TOWORD(d.data.ptr + 4, 3);     // 3 = delegate
2140                     TOWORD(d.data.ptr + 6, 2);     // count of type indices to follow
2141                     TOWORD(d.data.ptr + 8, key);   // type of 'this', which is void*
2142                     TOWORD(d.data.ptr + 10, next); // function type
2143 }
2144 else
2145 {
2146                     d = debtyp_alloc(6);
2147                     TOWORD(d.data.ptr,LF_DELEGATE);
2148                     TOWORD(d.data.ptr + 2, key);   // type of 'this', which is void*
2149                     TOWORD(d.data.ptr + 4, next);  // function type
2150 }
2151                     typidx = cv_debtyp(d);
2152                     break;
2153 
2154                 default:
2155                     assert(0);
2156             }
2157             break;
2158 
2159         case TYcent:
2160             if (t.Tnext)
2161                 goto Ldelegate;
2162             assert(dt);
2163             typidx = dt;
2164             break;
2165 
2166         case TYucent:
2167             if (t.Tnext)
2168                 goto Ldarray;
2169             assert(dt);
2170             typidx = dt;
2171             break;
2172 
2173         case TYarray:
2174         {   if (t.Tflags & TFsizeunknown)
2175                 size = 0;               // don't complain if don't know size
2176             else
2177                 size = type_size(t);
2178         Larray:
2179             u = cv4_numericbytes(cast(uint)size);
2180             uint idxtype = I32 ? 0x12 : 0x11;  // T_LONG : T_SHORT
2181             if (I64)
2182                 idxtype = 0x23;                    // T_UQUAD
2183             if(next == dttab4[TYvoid])    // do not encode void[n], this confuses the debugger
2184                 next = dttab4[TYuchar];   // use ubyte instead
2185             switch (config.fulltypes)
2186             {
2187                 case CV8:
2188                     d = debtyp_alloc(10 + u + 1);
2189                     TOWORD(d.data.ptr,0x1503);
2190                     TOLONG(d.data.ptr + 2,next);
2191                     TOLONG(d.data.ptr + 6,idxtype);
2192                     d.data.ptr[10 + u] = 0;             // no name
2193                     cv4_storenumeric(d.data.ptr + 10,cast(uint)size);
2194                     break;
2195 
2196                 case CV4:
2197                     d = debtyp_alloc(6 + u + 1);
2198                     TOWORD(d.data.ptr,LF_ARRAY);
2199                     TOWORD(d.data.ptr + 2,next);
2200                     TOWORD(d.data.ptr + 4,idxtype);
2201                     d.data.ptr[6 + u] = 0;             // no name
2202                     cv4_storenumeric(d.data.ptr + 6,cast(uint)size);
2203                     break;
2204 
2205                 default:
2206                     d = debtyp_alloc(10 + u + 1);
2207                     TOWORD(d.data.ptr,LF_ARRAY);
2208                     TOLONG(d.data.ptr + 2,next);
2209                     TOLONG(d.data.ptr + 6,idxtype);
2210                     d.data.ptr[10 + u] = 0;            // no name
2211                     cv4_storenumeric(d.data.ptr + 10,cast(uint)size);
2212                     break;
2213             }
2214             typidx = cv_debtyp(d);
2215             break;
2216         }
2217 
2218         case TYffunc:
2219         case TYfpfunc:
2220         case TYf16func:
2221         case TYfsfunc:
2222         case TYnsysfunc:
2223         case TYfsysfunc:
2224         case TYnfunc:
2225         case TYnpfunc:
2226         case TYnsfunc:
2227         case TYmfunc:
2228         case TYjfunc:
2229         case TYifunc:
2230         {
2231             param_t *p;
2232             uint nparam;
2233             idx_t paramidx;
2234 
2235             call = cv4_callconv(t);
2236             paramidx = cv4_arglist(t,&nparam);
2237 
2238             // Construct an LF_PROCEDURE
2239             switch (config.fulltypes)
2240             {
2241                 case CV8:
2242                     d = debtyp_alloc(2 + 4 + 1 + 1 + 2 + 4);
2243                     TOWORD(d.data.ptr,LF_PROCEDURE_V2);
2244                     TOLONG(d.data.ptr + 2,next);       // return type
2245                     d.data.ptr[6] = call;
2246                     d.data.ptr[7] = 0;                 // reserved
2247                     TOWORD(d.data.ptr + 8,nparam);
2248                     TOLONG(d.data.ptr + 10,paramidx);
2249                     break;
2250 
2251                 case CV4:
2252                     d = debtyp_alloc(2 + 2 + 1 + 1 + 2 + 2);
2253                     TOWORD(d.data.ptr,LF_PROCEDURE);
2254                     TOWORD(d.data.ptr + 2,next);               // return type
2255                     d.data.ptr[4] = call;
2256                     d.data.ptr[5] = 0;                 // reserved
2257                     TOWORD(d.data.ptr + 6,nparam);
2258                     TOWORD(d.data.ptr + 8,paramidx);
2259                     break;
2260 
2261                 default:
2262                     d = debtyp_alloc(2 + 4 + 1 + 1 + 2 + 4);
2263                     TOWORD(d.data.ptr,LF_PROCEDURE);
2264                     TOLONG(d.data.ptr + 2,next);               // return type
2265                     d.data.ptr[6] = call;
2266                     d.data.ptr[7] = 0;                 // reserved
2267                     TOWORD(d.data.ptr + 8,nparam);
2268                     TOLONG(d.data.ptr + 10,paramidx);
2269                     break;
2270             }
2271 
2272             typidx = cv_debtyp(d);
2273             break;
2274         }
2275 
2276         case TYstruct:
2277         {
2278             if (config.fulltypes == CV8)
2279             {
2280 version (MARS)
2281 {
2282                 typidx = cv8_fwdref(t.Ttag);
2283 }
2284             }
2285             else
2286             {
2287                 int foo = t.Ttag.Stypidx;
2288                 typidx = cv4_struct(t.Ttag,0);
2289                 //printf("struct '%s' %x %x\n", t.Ttag.Sident.ptr, foo, typidx);
2290             }
2291             break;
2292         }
2293 
2294         case TYenum:
2295             if (CPP)
2296             {
2297 version (SCPP)
2298 {
2299                 typidx = cv4_enum(t.Ttag);
2300 }
2301             }
2302             else
2303                 typidx = cv4_fwdenum(t);
2304             break;
2305 
2306 version (SCPP)
2307 {
2308         case TYvtshape:
2309         {   uint count;
2310             ubyte *p;
2311             ubyte descriptor;
2312 
2313             count = 1 + list_nitems(t.Ttag.Sstruct.Svirtual);
2314             d = debtyp_alloc(4 + ((count + 1) >> 1));
2315             p = d.data.ptr;
2316             TOWORD(p,LF_VTSHAPE);
2317             TOWORD(p + 2,count);
2318             descriptor = I32 ? 0x55 : (LARGECODE ? 0x11 : 0);
2319             memset(p + 4,descriptor,(count + 1) >> 1);
2320 
2321             typidx = cv_debtyp(d);
2322             break;
2323         }
2324 
2325         case TYref:
2326         case TYnref:
2327         case TYfref:
2328             attribute |= 0x20;          // indicate reference pointer
2329             goto case;
2330 
2331         case TYmemptr:
2332             tym = tybasic(tym_conv(t)); // convert to C data type
2333             goto L1;                    // and try again
2334 }
2335 
2336 version (MARS)
2337 {
2338         case TYref:
2339         case TYnref:
2340             attribute |= 0x20;          // indicate reference pointer
2341             tym = TYnptr;               // convert to C data type
2342             goto L1;                    // and try again
2343 }
2344 
2345         case TYnullptr:
2346             tym = TYnptr;
2347             next = cv4_typidx(tstypes[TYvoid]);  // rewrite as void*
2348             t = tspvoid;
2349             goto L1;
2350 
2351         // vector types
2352         case TYfloat4:  size = 16; next = dttab4[TYfloat];  goto Larray;
2353         case TYdouble2: size = 16; next = dttab4[TYdouble]; goto Larray;
2354         case TYschar16: size = 16; next = dttab4[TYschar];  goto Larray;
2355         case TYuchar16: size = 16; next = dttab4[TYuchar];  goto Larray;
2356         case TYshort8:  size = 16; next = dttab4[TYshort];  goto Larray;
2357         case TYushort8: size = 16; next = dttab4[TYushort]; goto Larray;
2358         case TYlong4:   size = 16; next = dttab4[TYlong];   goto Larray;
2359         case TYulong4:  size = 16; next = dttab4[TYulong];  goto Larray;
2360         case TYllong2:  size = 16; next = dttab4[TYllong];  goto Larray;
2361         case TYullong2: size = 16; next = dttab4[TYullong]; goto Larray;
2362 
2363         case TYfloat8:   size = 32; next = dttab4[TYfloat];  goto Larray;
2364         case TYdouble4:  size = 32; next = dttab4[TYdouble]; goto Larray;
2365         case TYschar32:  size = 32; next = dttab4[TYschar];  goto Larray;
2366         case TYuchar32:  size = 32; next = dttab4[TYuchar];  goto Larray;
2367         case TYshort16:  size = 32; next = dttab4[TYshort];  goto Larray;
2368         case TYushort16: size = 32; next = dttab4[TYushort]; goto Larray;
2369         case TYlong8:    size = 32; next = dttab4[TYlong];   goto Larray;
2370         case TYulong8:   size = 32; next = dttab4[TYulong];  goto Larray;
2371         case TYllong4:   size = 32; next = dttab4[TYllong];  goto Larray;
2372         case TYullong4:  size = 32; next = dttab4[TYullong]; goto Larray;
2373 
2374         case TYfloat16:  size = 64; next = dttab4[TYfloat];  goto Larray;
2375         case TYdouble8:  size = 64; next = dttab4[TYdouble]; goto Larray;
2376         case TYschar64:  size = 64; next = dttab4[TYschar];  goto Larray;
2377         case TYuchar64:  size = 64; next = dttab4[TYuchar];  goto Larray;
2378         case TYshort32:  size = 64; next = dttab4[TYshort];  goto Larray;
2379         case TYushort32: size = 64; next = dttab4[TYushort]; goto Larray;
2380         case TYlong16:   size = 64; next = dttab4[TYlong];   goto Larray;
2381         case TYulong16:  size = 64; next = dttab4[TYulong];  goto Larray;
2382         case TYllong8:   size = 64; next = dttab4[TYllong];  goto Larray;
2383         case TYullong8:  size = 64; next = dttab4[TYullong]; goto Larray;
2384 
2385         default:
2386             debug
2387             WRTYxx(tym);
2388 
2389             assert(0);
2390     }
2391 
2392     // Add in const and/or volatile modifiers
2393     if (tycv & (mTYconst | mTYimmutable | mTYvolatile))
2394     {   uint modifier;
2395 
2396         modifier = (tycv & (mTYconst | mTYimmutable)) ? 1 : 0;
2397         modifier |= (tycv & mTYvolatile) ? 2 : 0;
2398         switch (config.fulltypes)
2399         {
2400             case CV8:
2401                 d = debtyp_alloc(8);
2402                 TOWORD(d.data.ptr,0x1001);
2403                 TOLONG(d.data.ptr + 2,typidx);
2404                 TOWORD(d.data.ptr + 6,modifier);
2405                 break;
2406 
2407             case CV4:
2408                 d = debtyp_alloc(6);
2409                 TOWORD(d.data.ptr,LF_MODIFIER);
2410                 TOWORD(d.data.ptr + 2,modifier);
2411                 TOWORD(d.data.ptr + 4,typidx);
2412                 break;
2413 
2414             default:
2415                 d = debtyp_alloc(10);
2416                 TOWORD(d.data.ptr,LF_MODIFIER);
2417                 TOLONG(d.data.ptr + 2,modifier);
2418                 TOLONG(d.data.ptr + 6,typidx);
2419                 break;
2420         }
2421         typidx = cv_debtyp(d);
2422     }
2423 
2424     assert(typidx);
2425     return typidx;
2426 }
2427 
2428 /******************************************
2429  * Write out symbol s.
2430  */
2431 
2432 private void cv4_outsym(Symbol *s)
2433 {
2434     uint len;
2435     type *t;
2436     uint length;
2437     uint u;
2438     tym_t tym;
2439     const(char)* id;
2440     ubyte *debsym = null;
2441     ubyte[64] buf = void;
2442 
2443     //printf("cv4_outsym(%s)\n",s.Sident.ptr);
2444     symbol_debug(s);
2445 version (MARS)
2446 {
2447     if (s.Sflags & SFLnodebug)
2448         return;
2449 }
2450     t = s.Stype;
2451     type_debug(t);
2452     tym = tybasic(t.Tty);
2453     if (tyfunc(tym) && s.Sclass != SCtypedef)
2454     {   int framedatum,targetdatum,fd;
2455         char idfree;
2456         idx_t typidx;
2457 
2458         if (s != funcsym_p)
2459             return;
2460 version (SCPP)
2461 {
2462         if (CPP && isclassmember(s))            // if method
2463         {   Outbuffer buf2;
2464 
2465             param_tostring(&buf2,s.Stype);
2466             buf2.prependBytes(cpp_prettyident(s));
2467             char* s2 = buf2.toString();
2468             const len2 = strlen(s2);
2469             id = cast(char*)alloca(len2 + 1);
2470             assert(id);
2471             memcpy(cast(void*)id, s2, len2 + 1);
2472         }
2473         else
2474         {
2475             id = prettyident(s);
2476         }
2477 }
2478 else
2479 {
2480         id = s.prettyIdent ? s.prettyIdent : s.Sident.ptr;
2481 }
2482         len = cv_stringbytes(id);
2483 
2484         // Length of record
2485         length = 2 + 2 + 4 * 3 + _tysize[TYint] * 4 + 2 + cgcv.sz_idx + 1;
2486         debsym = (length + len <= (buf).sizeof) ? buf.ptr : cast(ubyte *) malloc(length + len);
2487         assert(debsym);
2488         memset(debsym,0,length + len);
2489 
2490         // Symbol type
2491         u = (s.Sclass == SCstatic) ? S_LPROC16 : S_GPROC16;
2492         if (I32)
2493             u += S_GPROC32 - S_GPROC16;
2494         TOWORD(debsym + 2,u);
2495 
2496         if (config.fulltypes == CV4)
2497         {
2498             // Offsets
2499             if (I32)
2500             {   TOLONG(debsym + 16,cast(uint)s.Ssize);           // proc length
2501                 TOLONG(debsym + 20,cast(uint)startoffset);        // debug start
2502                 TOLONG(debsym + 24,cast(uint)retoffset);          // debug end
2503                 u = 28;                                 // offset to fixup
2504             }
2505             else
2506             {   TOWORD(debsym + 16,cast(uint)s.Ssize);           // proc length
2507                 TOWORD(debsym + 18,cast(uint)startoffset);        // debug start
2508                 TOWORD(debsym + 20,cast(uint)retoffset);          // debug end
2509                 u = 22;                                 // offset to fixup
2510             }
2511             length += cv_namestring(debsym + u + _tysize[TYint] + 2 + cgcv.sz_idx + 1,id);
2512             typidx = cv4_symtypidx(s);
2513             TOIDX(debsym + u + _tysize[TYint] + 2,typidx);     // proc type
2514             debsym[u + _tysize[TYint] + 2 + cgcv.sz_idx] = tyfarfunc(tym) ? 4 : 0;
2515             TOWORD(debsym,length - 2);
2516         }
2517         else
2518         {
2519             // Offsets
2520             if (I32)
2521             {   TOLONG(debsym + 16 + cgcv.sz_idx,cast(uint)s.Ssize);             // proc length
2522                 TOLONG(debsym + 20 + cgcv.sz_idx,cast(uint)startoffset);  // debug start
2523                 TOLONG(debsym + 24 + cgcv.sz_idx,cast(uint)retoffset);            // debug end
2524                 u = 28;                                         // offset to fixup
2525             }
2526             else
2527             {   TOWORD(debsym + 16 + cgcv.sz_idx,cast(uint)s.Ssize);             // proc length
2528                 TOWORD(debsym + 18 + cgcv.sz_idx,cast(uint)startoffset);  // debug start
2529                 TOWORD(debsym + 20 + cgcv.sz_idx,cast(uint)retoffset);            // debug end
2530                 u = 22;                                         // offset to fixup
2531             }
2532             u += cgcv.sz_idx;
2533             length += cv_namestring(debsym + u + _tysize[TYint] + 2 + 1,id);
2534             typidx = cv4_symtypidx(s);
2535             TOIDX(debsym + 16,typidx);                  // proc type
2536             debsym[u + _tysize[TYint] + 2] = tyfarfunc(tym) ? 4 : 0;
2537             TOWORD(debsym,length - 2);
2538         }
2539 
2540         uint soffset = cast(uint)Offset(DEBSYM);
2541         objmod.write_bytes(SegData[DEBSYM],length,debsym);
2542 
2543         // Put out fixup for function start offset
2544         objmod.reftoident(DEBSYM,soffset + u,s,0,CFseg | CFoff);
2545     }
2546     else
2547     {   targ_size_t base;
2548         int reg;
2549         uint fd;
2550         uint idx1,idx2;
2551         uint value;
2552         uint fixoff;
2553         idx_t typidx;
2554 
2555         typidx = cv4_typidx(t);
2556 version (MARS)
2557 {
2558         id = s.prettyIdent ? s.prettyIdent : prettyident(s);
2559 }
2560 else
2561 {
2562         id = prettyident(s);
2563 }
2564         len = cast(uint)strlen(id);
2565         debsym = (39 + IDOHD + len <= (buf).sizeof) ? buf.ptr : cast(ubyte *) malloc(39 + IDOHD + len);
2566         assert(debsym);
2567         switch (s.Sclass)
2568         {
2569             case SCparameter:
2570             case SCregpar:
2571                 if (s.Sfl == FLreg)
2572                 {
2573                     s.Sfl = FLpara;
2574                     cv4_outsym(s);
2575                     s.Sfl = FLreg;
2576                     goto case_register;
2577                 }
2578                 base = Para.size - BPoff;    // cancel out add of BPoff
2579                 goto L1;
2580 
2581             case SCauto:
2582                 if (s.Sfl == FLreg)
2583                     goto case_register;
2584             case_auto:
2585                 base = Auto.size;
2586             L1:
2587                 if (s.Sscope) // local variables moved into the closure cannot be emitted directly
2588                     goto Lret;
2589                 TOWORD(debsym + 2,I32 ? S_BPREL32 : S_BPREL16);
2590                 if (config.fulltypes == CV4)
2591                 {   TOOFFSET(debsym + 4,s.Soffset + base + BPoff);
2592                     TOIDX(debsym + 4 + _tysize[TYint],typidx);
2593                 }
2594                 else
2595                 {   TOOFFSET(debsym + 4 + cgcv.sz_idx,s.Soffset + base + BPoff);
2596                     TOIDX(debsym + 4,typidx);
2597                 }
2598                 length = 2 + 2 + _tysize[TYint] + cgcv.sz_idx;
2599                 length += cv_namestring(debsym + length,id);
2600                 TOWORD(debsym,length - 2);
2601                 break;
2602 
2603             case SCbprel:
2604                 base = -BPoff;
2605                 goto L1;
2606 
2607             case SCfastpar:
2608                 if (s.Sfl != FLreg)
2609                 {   base = Fast.size;
2610                     goto L1;
2611                 }
2612                 goto case_register;
2613 
2614             case SCregister:
2615                 if (s.Sfl != FLreg)
2616                     goto case_auto;
2617                 goto case_register;
2618 
2619             case SCpseudo:
2620             case_register:
2621                 TOWORD(debsym + 2,S_REGISTER);
2622                 reg = cv_regnum(s);
2623                 TOIDX(debsym + 4,typidx);
2624                 TOWORD(debsym + 4 + cgcv.sz_idx,reg);
2625                 length = 2 * 3 + cgcv.sz_idx;
2626                 length += 1 + cv_namestring(debsym + length,id);
2627                 TOWORD(debsym,length - 2);
2628                 break;
2629 
2630             case SCextern:
2631             case SCcomdef:
2632                 // Common blocks have a non-zero Sxtrnnum and an UNKNOWN seg
2633                 if (!(s.Sxtrnnum && s.Sseg == UNKNOWN)) // if it's not really a common block
2634                 {
2635                         goto Lret;
2636                 }
2637                 goto case;
2638             case SCglobal:
2639             case SCcomdat:
2640                 u = S_GDATA16;
2641                 goto L2;
2642 
2643             case SCstatic:
2644             case SClocstat:
2645                 u = S_LDATA16;
2646             L2:
2647                 if (I32)
2648                     u += S_GDATA32 - S_GDATA16;
2649                 TOWORD(debsym + 2,u);
2650                 if (config.fulltypes == CV4)
2651                 {
2652                     fixoff = 4;
2653                     length = 2 + 2 + _tysize[TYint] + 2;
2654                     TOOFFSET(debsym + fixoff,s.Soffset);
2655                     TOWORD(debsym + fixoff + _tysize[TYint],0);
2656                     TOIDX(debsym + length,typidx);
2657                 }
2658                 else
2659                 {
2660                     fixoff = 8;
2661                     length = 2 + 2 + _tysize[TYint] + 2;
2662                     TOOFFSET(debsym + fixoff,s.Soffset);
2663                     TOWORD(debsym + fixoff + _tysize[TYint],0);        // segment
2664                     TOIDX(debsym + 4,typidx);
2665                 }
2666                 length += cgcv.sz_idx;
2667                 length += cv_namestring(debsym + length,id);
2668                 TOWORD(debsym,length - 2);
2669                 assert(length <= 40 + len);
2670 
2671                 if (s.Sseg == UNKNOWN || s.Sclass == SCcomdat) // if common block
2672                 {
2673                     if (config.exe & EX_flat)
2674                     {
2675                         fd = 0x16;
2676                         idx1 = DGROUPIDX;
2677                         idx2 = s.Sxtrnnum;
2678                     }
2679                     else
2680                     {
2681                         fd = 0x26;
2682                         idx1 = idx2 = s.Sxtrnnum;
2683                     }
2684                 }
2685                 else if (s.ty() & (mTYfar | mTYcs))
2686                 {
2687                     fd = 0x04;
2688                     idx1 = idx2 = SegData[s.Sseg].segidx;
2689                 }
2690                 else
2691                 {   fd = 0x14;
2692                     idx1 = DGROUPIDX;
2693                     idx2 = SegData[s.Sseg].segidx;
2694                 }
2695                 /* Because of the linker limitations, the length cannot
2696                  * exceed 0x1000.
2697                  * See optlink\cv\cvhashes.asm
2698                  */
2699                 assert(length <= 0x1000);
2700                 if (idx2 != 0)
2701                 {   uint offset = cast(uint)Offset(DEBSYM);
2702                     objmod.write_bytes(SegData[DEBSYM],length,debsym);
2703                     objmod.write_long(DEBSYM,offset + fixoff,cast(uint)s.Soffset,
2704                         cgcv.LCFDpointer + fd,idx1,idx2);
2705                 }
2706                 goto Lret;
2707 
2708 static if (1)
2709 {
2710             case SCtypedef:
2711                 s.Stypidx = typidx;
2712                 reset_symbuf.write((&s)[0 .. 1]);
2713                 goto L4;
2714 
2715             case SCstruct:
2716                 if (s.Sstruct.Sflags & STRnotagname)
2717                     goto Lret;
2718                 goto L4;
2719 
2720             case SCenum:
2721 version (SCPP)
2722 {
2723                 if (CPP && s.Senum.SEflags & SENnotagname)
2724                     goto Lret;
2725 }
2726             L4:
2727                 // Output a 'user-defined type' for the tag name
2728                 TOWORD(debsym + 2,S_UDT);
2729                 TOIDX(debsym + 4,typidx);
2730                 length = 2 + 2 + cgcv.sz_idx;
2731                 length += cv_namestring(debsym + length,id);
2732                 TOWORD(debsym,length - 2);
2733                 list_subtract(&cgcv.list,s);
2734                 break;
2735 
2736             case SCconst:
2737                 // The only constants are enum members
2738                 value = cast(uint)el_tolongt(s.Svalue);
2739                 TOWORD(debsym + 2,S_CONST);
2740                 TOIDX(debsym + 4,typidx);
2741                 length = 4 + cgcv.sz_idx;
2742                 cv4_storenumeric(debsym + length,value);
2743                 length += cv4_numericbytes(value);
2744                 length += cv_namestring(debsym + length,id);
2745                 TOWORD(debsym,length - 2);
2746                 break;
2747 }
2748             default:
2749                 goto Lret;
2750         }
2751         assert(length <= 40 + len);
2752         objmod.write_bytes(SegData[DEBSYM],length,debsym);
2753     }
2754 Lret:
2755     if (debsym != buf.ptr)
2756         free(debsym);
2757 }
2758 
2759 /******************************************
2760  * Write out any deferred symbols.
2761  */
2762 
2763 private void cv_outlist()
2764 {
2765     while (cgcv.list)
2766         cv_outsym(cast(Symbol *) list_pop(&cgcv.list));
2767 }
2768 
2769 /******************************************
2770  * Write out symbol table for current function.
2771  */
2772 
2773 private void cv4_func(Funcsym *s, ref symtab_t symtab)
2774 {
2775     int endarg;
2776 
2777     cv4_outsym(s);              // put out function symbol
2778 version (MARS)
2779 {
2780     __gshared Funcsym* sfunc;
2781     __gshared int cntOpenBlocks;
2782     sfunc = s;
2783     cntOpenBlocks = 0;
2784 
2785     struct cv4
2786     {
2787     nothrow:
2788         // record for CV record S_BLOCK32
2789         struct block32_data
2790         {
2791             ushort len;
2792             ushort id;
2793             uint pParent;
2794             uint pEnd;
2795             uint length;
2796             uint offset;
2797             ushort seg;
2798             ubyte[2] name;
2799         }
2800 
2801       extern (C++):
2802 
2803         static void endArgs()
2804         {
2805             __gshared ushort[2] endargs = [ 2, S_ENDARG ];
2806             objmod.write_bytes(SegData[DEBSYM],(endargs).sizeof,endargs.ptr);
2807         }
2808         static void beginBlock(int offset, int length)
2809         {
2810             if (++cntOpenBlocks >= 255)
2811                 return; // optlink does not like more than 255 scope blocks
2812 
2813             uint soffset = cast(uint)Offset(DEBSYM);
2814             // parent and end to be filled by linker
2815             block32_data block32 = { (block32_data).sizeof - 2, S_BLOCK32, 0, 0, length, 0, 0, [ 0, '\0' ] };
2816             objmod.write_bytes(SegData[DEBSYM], (block32).sizeof, &block32);
2817             size_t offOffset = cast(char*)&block32.offset - cast(char*)&block32;
2818             objmod.reftoident(DEBSYM, soffset + offOffset, sfunc, offset + sfunc.Soffset, CFseg | CFoff);
2819         }
2820         static void endBlock()
2821         {
2822             if (cntOpenBlocks-- >= 255)
2823                 return; // optlink does not like more than 255 scope blocks
2824 
2825             __gshared ushort[2] endargs = [ 2, S_END ];
2826             objmod.write_bytes(SegData[DEBSYM],(endargs).sizeof,endargs.ptr);
2827         }
2828     }
2829 
2830     varStats_writeSymbolTable(symtab, &cv4_outsym, &cv4.endArgs, &cv4.beginBlock, &cv4.endBlock);
2831 }
2832 else
2833 {
2834     // Put out local symbols
2835     endarg = 0;
2836     foreach (sa; symtab[])
2837     {   //printf("symtab[%d] = %p\n",si,symtab[si]);
2838         cv4_outsym(sa);
2839     }
2840 }
2841 
2842     // Put out function return record
2843     if (1)
2844     {   ubyte[2+2+2+1+1+4] sreturn = void;
2845         ushort flags;
2846         ubyte style;
2847         tym_t ty;
2848         tym_t tyret;
2849         uint u;
2850 
2851         u = 2+2+1;
2852         ty = tybasic(s.ty());
2853 
2854         flags = tyrevfunc(ty) ? 0 : 1;
2855         flags |= typfunc(ty) ? 0 : 2;
2856         TOWORD(sreturn.ptr + 4,flags);
2857 
2858         tyret = tybasic(s.Stype.Tnext.Tty);
2859         switch (tyret)
2860         {
2861             case TYvoid:
2862             default:
2863                 style = 0;
2864                 break;
2865 
2866             case TYbool:
2867             case TYchar:
2868             case TYschar:
2869             case TYuchar:
2870                 sreturn[7] = 1;
2871                 sreturn[8] = 1;         // AL
2872                 goto L1;
2873 
2874             case TYwchar_t:
2875             case TYchar16:
2876             case TYshort:
2877             case TYushort:
2878                 goto case_ax;
2879 
2880             case TYint:
2881             case TYuint:
2882             case TYsptr:
2883             case TYcptr:
2884             case TYnullptr:
2885             case TYnptr:
2886             case TYnref:
2887                 if (I32)
2888                     goto case_eax;
2889                 else
2890                     goto case_ax;
2891 
2892             case TYfloat:
2893             case TYifloat:
2894                 if (config.exe & EX_flat)
2895                     goto case_st0;
2896                 goto case;
2897 
2898             case TYlong:
2899             case TYulong:
2900             case TYdchar:
2901                 if (I32)
2902                     goto case_eax;
2903                 else
2904                     goto case_dxax;
2905 
2906             case TYfptr:
2907             case TYhptr:
2908                 if (I32)
2909                     goto case_edxeax;
2910                 else
2911                     goto case_dxax;
2912 
2913             case TYvptr:
2914                 if (I32)
2915                     goto case_edxebx;
2916                 else
2917                     goto case_dxbx;
2918 
2919             case TYdouble:
2920             case TYidouble:
2921             case TYdouble_alias:
2922                 if (config.exe & EX_flat)
2923                     goto case_st0;
2924                 if (I32)
2925                     goto case_edxeax;
2926                 else
2927                     goto case_axbxcxdx;
2928 
2929             case TYllong:
2930             case TYullong:
2931                 assert(I32);
2932                 goto case_edxeax;
2933 
2934             case TYldouble:
2935             case TYildouble:
2936                 goto case_st0;
2937 
2938             case TYcfloat:
2939             case TYcdouble:
2940             case TYcldouble:
2941                 goto case_st01;
2942 
2943             case_ax:
2944                 sreturn[7] = 1;
2945                 sreturn[8] = 9;         // AX
2946                 goto L1;
2947 
2948             case_eax:
2949                 sreturn[7] = 1;
2950                 sreturn[8] = 17;        // EAX
2951                 goto L1;
2952 
2953 
2954             case_dxax:
2955                 sreturn[7] = 2;
2956                 sreturn[8] = 11;        // DX
2957                 sreturn[9] = 9;         // AX
2958                 goto L1;
2959 
2960             case_dxbx:
2961                 sreturn[7] = 2;
2962                 sreturn[8] = 11;        // DX
2963                 sreturn[9] = 12;        // BX
2964                 goto L1;
2965 
2966             case_axbxcxdx:
2967                 sreturn[7] = 4;
2968                 sreturn[8] = 9;         // AX
2969                 sreturn[9] = 12;        // BX
2970                 sreturn[10] = 10;       // CX
2971                 sreturn[11] = 11;       // DX
2972                 goto L1;
2973 
2974             case_edxeax:
2975                 sreturn[7] = 2;
2976                 sreturn[8] = 19;        // EDX
2977                 sreturn[9] = 17;        // EAX
2978                 goto L1;
2979 
2980             case_edxebx:
2981                 sreturn[7] = 2;
2982                 sreturn[8] = 19;        // EDX
2983                 sreturn[9] = 20;        // EBX
2984                 goto L1;
2985 
2986             case_st0:
2987                 sreturn[7] = 1;
2988                 sreturn[8] = 128;       // ST0
2989                 goto L1;
2990 
2991             case_st01:
2992                 sreturn[7] = 2;
2993                 sreturn[8] = 128;       // ST0 (imaginary)
2994                 sreturn[9] = 129;       // ST1 (real)
2995                 goto L1;
2996 
2997             L1:
2998                 style = 1;
2999                 u += sreturn[7] + 1;
3000                 break;
3001         }
3002         sreturn[6] = style;
3003 
3004         TOWORD(sreturn.ptr,u);
3005         TOWORD(sreturn.ptr + 2,S_RETURN);
3006         objmod.write_bytes(SegData[DEBSYM],u + 2,sreturn.ptr);
3007     }
3008 
3009     // Put out end scope
3010     {   __gshared ushort[2] endproc = [ 2,S_END ];
3011 
3012         objmod.write_bytes(SegData[DEBSYM],(endproc).sizeof,endproc.ptr);
3013     }
3014 
3015     cv_outlist();
3016 }
3017 
3018 //////////////////////////////////////////////////////////
3019 
3020 /******************************************
3021  * Write out data to .OBJ file.
3022  */
3023 
3024 void cv_term()
3025 {
3026     //printf("cv_term(): debtyp.length = %d\n",debtyp.length);
3027 
3028     segidx_t typeseg = objmod.seg_debugT();
3029 
3030     switch (config.fulltypes)
3031     {
3032         case CV4:
3033         case CVSYM:
3034             cv_outlist();
3035             goto case;
3036         case CV8:
3037             objmod.write_bytes(SegData[typeseg],4,&cgcv.signature);
3038             if (debtyp.length != 1 || config.fulltypes == CV8)
3039             {
3040                 for (uint u = 0; u < debtyp.length; u++)
3041                 {   debtyp_t *d = debtyp[u];
3042 
3043                     objmod.write_bytes(SegData[typeseg],2 + d.length,cast(char *)d + uint.sizeof);
3044                     debtyp_free(d);
3045                 }
3046             }
3047             else if (debtyp.length)
3048             {
3049                 debtyp_free(debtyp[0]);
3050             }
3051             break;
3052 
3053 static if (SYMDEB_TDB)
3054 {
3055         case CVTDB:
3056             cv_outlist();
3057 static if (1)
3058 {
3059             tdb_term();
3060 }
3061 else
3062 {
3063         {   ubyte *buf;
3064             ubyte *p;
3065             size_t len;
3066 
3067             // Calculate size of buffer
3068             len = 4;
3069             for (uint u = 0; u < debtyp.length; u++)
3070             {   debtyp_t *d = debtyp[u];
3071 
3072                 len += 2 + d.length;
3073             }
3074 
3075             // Allocate buffer
3076             buf = malloc(len);
3077             if (!buf)
3078                 err_nomem();                    // out of memory
3079 
3080             // Fill the buffer
3081             TOLONG(buf,cgcv.signature);
3082             p = buf + 4;
3083             for (uint u = 0; u < debtyp.length; u++)
3084             {   debtyp_t *d = debtyp[u];
3085 
3086                 len = 2 + d.length;
3087                 memcpy(p,cast(char *)d + uint.sizeof,len);
3088                 p += len;
3089             }
3090 
3091             tdb_write(buf,len,debtyp.length);
3092         }
3093 }
3094             break;
3095 }
3096 
3097         default:
3098             assert(0);
3099     }
3100 
3101     // debtyp.dtor();  // save for later
3102     vec_free(debtypvec);
3103     debtypvec = null;
3104 }
3105 
3106 /******************************************
3107  * Write out symbol table for current function.
3108  */
3109 
3110 void cv_func(Funcsym *s)
3111 {
3112 version (SCPP)
3113 {
3114     if (errcnt)                 // if we had any errors
3115         return;                 // don't bother putting stuff in .OBJ file
3116 }
3117 
3118     //printf("cv_func('%s')\n",s.Sident.ptr);
3119 version (MARS)
3120 {
3121     if (s.Sflags & SFLnodebug)
3122         return;
3123 }
3124 else
3125 {
3126     if (CPP && s.Sfunc.Fflags & Fnodebug)     // if don't generate debug info
3127         return;
3128 }
3129     switch (config.fulltypes)
3130     {
3131         case CV4:
3132         case CVSYM:
3133         case CVTDB:
3134             cv4_func(s, globsym);
3135             break;
3136 
3137         default:
3138             assert(0);
3139     }
3140 }
3141 
3142 /******************************************
3143  * Write out symbol table for current function.
3144  */
3145 
3146 void cv_outsym(Symbol *s)
3147 {
3148     //printf("cv_outsym('%s')\n",s.Sident.ptr);
3149     symbol_debug(s);
3150 version (MARS)
3151 {
3152     if (s.Sflags & SFLnodebug)
3153         return;
3154 }
3155     switch (config.fulltypes)
3156     {
3157         case CV4:
3158         case CVSYM:
3159         case CVTDB:
3160             cv4_outsym(s);
3161             break;
3162 
3163 version (MARS)
3164 {
3165         case CV8:
3166             cv8_outsym(s);
3167             break;
3168 }
3169 
3170         default:
3171             assert(0);
3172     }
3173 }
3174 
3175 /******************************************
3176  * Return cv type index for a type.
3177  */
3178 
3179 uint cv_typidx(type *t)
3180 {   uint ti;
3181 
3182     //printf("cv_typidx(%p)\n",t);
3183     switch (config.fulltypes)
3184     {
3185         case CV4:
3186         case CVTDB:
3187         case CVSYM:
3188         case CV8:
3189             ti = cv4_typidx(t);
3190             break;
3191 
3192         default:
3193             debug
3194             printf("fulltypes = %d\n",config.fulltypes);
3195 
3196             assert(0);
3197     }
3198     return ti;
3199 }
3200 
3201 }