1 /** 2 * Transition from intermediate representation to code generator 3 * 4 * Compiler implementation of the 5 * $(LINK2 https://www.dlang.org, D programming language). 6 * 7 * Copyright: Copyright (C) 1984-1998 by Symantec 8 * Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved 9 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 10 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 11 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/out.d, backend/out.d) 12 */ 13 14 module dmd.backend.dout; 15 16 import core.stdc.stdio; 17 import core.stdc.string; 18 19 import dmd.backend.cc; 20 import dmd.backend.cdef; 21 import dmd.backend.cgcv; 22 import dmd.backend.code; 23 import dmd.backend.code_x86; 24 import dmd.backend.cv4; 25 import dmd.backend.dt; 26 import dmd.backend.dlist; 27 import dmd.backend.mem; 28 import dmd.backend.el; 29 import dmd.backend.global; 30 import dmd.backend.goh; 31 import dmd.backend.inliner; 32 import dmd.backend.obj; 33 import dmd.backend.oper; 34 import dmd.backend.rtlsym; 35 import dmd.backend.symtab; 36 import dmd.backend.ty; 37 import dmd.backend.type; 38 39 import dmd.backend.barray; 40 41 version (Windows) 42 { 43 extern (C) 44 { 45 int stricmp(const(char)*, const(char)*) pure nothrow @nogc; 46 int memicmp(const(void)*, const(void)*, size_t) pure nothrow @nogc; 47 } 48 } 49 50 51 nothrow: 52 @safe: 53 54 // Determine if this Symbol is stored in a COMDAT 55 @trusted 56 bool symbol_iscomdat2(Symbol* s) 57 { 58 return s.Sclass == SC.comdat || 59 config.flags2 & CFG2comdat && s.Sclass == SC.inline || 60 config.flags4 & CFG4allcomdat && s.Sclass == SC.global; 61 } 62 63 /*********************************** 64 * Output function thunk. 65 */ 66 @trusted 67 extern (C) void outthunk(Symbol *sthunk,Symbol *sfunc,uint p,tym_t thisty, 68 targ_size_t d,int i,targ_size_t d2) 69 { 70 sthunk.Sseg = cseg; 71 cod3_thunk(sthunk,sfunc,p,thisty,cast(uint)d,i,cast(uint)d2); 72 sthunk.Sfunc.Fflags &= ~Fpending; 73 sthunk.Sfunc.Fflags |= Foutput; /* mark it as having been output */ 74 } 75 76 77 /*************************** 78 * Write out statically allocated data. 79 * Input: 80 * s symbol to be initialized 81 */ 82 @trusted 83 void outdata(Symbol *s) 84 { 85 int seg; 86 targ_size_t offset; 87 int flags; 88 const int codeseg = cseg; 89 90 symbol_debug(s); 91 92 debug 93 debugy && printf("outdata('%s')\n",s.Sident.ptr); 94 95 //printf("outdata('%s', ty=x%x)\n",s.Sident.ptr,s.Stype.Tty); 96 //symbol_print(s); 97 98 // Data segment variables are always live on exit from a function 99 s.Sflags |= SFLlivexit; 100 101 dt_t *dtstart = s.Sdt; 102 s.Sdt = null; // it will be free'd 103 targ_size_t datasize = 0; 104 tym_t ty = s.ty(); 105 if (ty & mTYexport && config.wflags & WFexpdef && s.Sclass != SC.static_) 106 objmod.export_symbol(s,0); // export data definition 107 for (dt_t *dt = dtstart; dt; dt = dt.DTnext) 108 { 109 //printf("\tdt = %p, dt = %d\n",dt,dt.dt); 110 switch (dt.dt) 111 { case DT_abytes: 112 { // Put out the data for the string, and 113 // reserve a spot for a pointer to that string 114 datasize += size(dt.Dty); // reserve spot for pointer to string 115 if (tybasic(dt.Dty) == TYcptr) 116 { dt.DTseg = codeseg; 117 dt.DTabytes += Offset(codeseg); 118 goto L1; 119 } 120 else if (tybasic(dt.Dty) == TYfptr && 121 dt.DTnbytes > config.threshold) 122 { 123 L1: 124 objmod.write_bytes(SegData[dt.DTseg],dt.DTpbytes[0 .. dt.DTnbytes]); 125 break; 126 } 127 else 128 { 129 alignOffset(CDATA, 2 << dt.DTalign); 130 dt.DTabytes += objmod.data_readonly(cast(char*)dt.DTpbytes,dt.DTnbytes,&dt.DTseg); 131 } 132 break; 133 } 134 135 case DT_ibytes: 136 datasize += dt.DTn; 137 break; 138 139 case DT_nbytes: 140 //printf("DT_nbytes %d\n", dt.DTnbytes); 141 datasize += dt.DTnbytes; 142 break; 143 144 case DT_azeros: 145 /* A block of zeros 146 */ 147 //printf("DT_azeros %d\n", dt.DTazeros); 148 datasize += dt.DTazeros; 149 if (dt == dtstart && !dt.DTnext && s.Sclass != SC.comdat && 150 (s.Sseg == UNKNOWN || s.Sseg <= UDATA)) 151 { /* first and only, so put in BSS segment 152 */ 153 switch (ty & mTYLINK) 154 { 155 case mTYcs: 156 s.Sseg = codeseg; 157 Offset(codeseg) = _align(datasize,Offset(codeseg)); 158 s.Soffset = Offset(codeseg); 159 Offset(codeseg) += datasize; 160 s.Sfl = FLcsdata; 161 break; 162 163 case mTYthreadData: 164 assert(config.objfmt == OBJ_MACH && I64); 165 goto case; 166 case mTYthread: 167 { seg_data *pseg = objmod.tlsseg_bss(); 168 s.Sseg = pseg.SDseg; 169 objmod.data_start(s, datasize, pseg.SDseg); 170 if (config.objfmt == OBJ_OMF) 171 pseg.SDoffset += datasize; 172 else 173 objmod.lidata(pseg.SDseg, pseg.SDoffset, datasize); 174 s.Sfl = FLtlsdata; 175 break; 176 } 177 178 default: 179 s.Sseg = UDATA; 180 objmod.data_start(s,datasize,UDATA); 181 objmod.lidata(s.Sseg,s.Soffset,datasize); 182 s.Sfl = FLudata; // uninitialized data 183 break; 184 } 185 assert(s.Sseg && s.Sseg != UNKNOWN); 186 if (s.Sclass == SC.global || (s.Sclass == SC.static_ && config.objfmt != OBJ_OMF)) // if a pubdef to be done 187 objmod.pubdefsize(s.Sseg,s,s.Soffset,datasize); // do the definition 188 if (config.fulltypes && 189 !(s.Sclass == SC.static_ && funcsym_p)) // not local static 190 { 191 if (config.objfmt == OBJ_ELF || config.objfmt == OBJ_MACH) 192 dwarf_outsym(s); 193 else 194 cv_outsym(s); 195 } 196 goto Lret; 197 } 198 break; 199 200 case DT_common: 201 assert(!dt.DTnext); 202 outcommon(s,dt.DTazeros); 203 goto Lret; 204 205 case DT_xoff: 206 { Symbol *sb = dt.DTsym; 207 208 if (tyfunc(sb.ty())) 209 { 210 } 211 else if (sb.Sdt) // if initializer for symbol 212 { if (!s.Sseg) s.Sseg = DATA; 213 outdata(sb); // write out data for symbol 214 } 215 } 216 goto case; 217 case DT_coff: 218 datasize += size(dt.Dty); 219 break; 220 default: 221 debug 222 printf("dt = %p, dt = %d\n",dt,dt.dt); 223 assert(0); 224 } 225 } 226 227 if (s.Sclass == SC.comdat) // if initialized common block 228 { 229 seg = objmod.comdatsize(s, datasize); 230 switch (ty & mTYLINK) 231 { 232 case mTYfar: // if far data 233 s.Sfl = FLfardata; 234 break; 235 236 case mTYcs: 237 s.Sfl = FLcsdata; 238 break; 239 240 case mTYnear: 241 case 0: 242 s.Sfl = FLdata; // initialized data 243 break; 244 245 case mTYthread: 246 s.Sfl = FLtlsdata; 247 break; 248 249 case mTYweakLinkage: 250 s.Sfl = FLdata; // initialized data 251 break; 252 253 default: 254 assert(0); 255 } 256 } 257 else 258 { 259 switch (ty & mTYLINK) 260 { 261 case mTYcs: 262 seg = codeseg; 263 Offset(codeseg) = _align(datasize,Offset(codeseg)); 264 s.Soffset = Offset(codeseg); 265 s.Sfl = FLcsdata; 266 break; 267 268 case mTYthreadData: 269 { 270 assert(config.objfmt == OBJ_MACH && I64); 271 272 seg_data *pseg = objmod.tlsseg_data(); 273 s.Sseg = pseg.SDseg; 274 objmod.data_start(s, datasize, s.Sseg); 275 seg = pseg.SDseg; 276 s.Sfl = FLtlsdata; 277 break; 278 } 279 case mTYthread: 280 { 281 seg_data *pseg = objmod.tlsseg(); 282 s.Sseg = pseg.SDseg; 283 objmod.data_start(s, datasize, s.Sseg); 284 seg = pseg.SDseg; 285 s.Sfl = FLtlsdata; 286 break; 287 } 288 case mTYnear: 289 case 0: 290 if ( 291 s.Sseg == 0 || 292 s.Sseg == UNKNOWN) 293 s.Sseg = DATA; 294 seg = objmod.data_start(s,datasize,DATA); 295 s.Sfl = FLdata; // initialized data 296 break; 297 298 default: 299 assert(0); 300 } 301 } 302 if (s.Sseg == UNKNOWN && (config.objfmt == OBJ_ELF || config.objfmt == OBJ_MACH)) 303 s.Sseg = seg; 304 else if (config.objfmt == OBJ_OMF) 305 s.Sseg = seg; 306 else 307 seg = s.Sseg; 308 309 if (s.Sclass == SC.global || (s.Sclass == SC.static_ && config.objfmt != OBJ_OMF)) 310 objmod.pubdefsize(seg,s,s.Soffset,datasize); /* do the definition */ 311 312 assert(s.Sseg != UNKNOWN); 313 if (config.fulltypes && 314 !(s.Sclass == SC.static_ && funcsym_p)) // not local static 315 { 316 if (config.objfmt == OBJ_ELF || config.objfmt == OBJ_MACH) 317 dwarf_outsym(s); 318 else 319 cv_outsym(s); 320 } 321 322 /* Go back through list, now that we know its size, and send out */ 323 /* the data. */ 324 325 offset = s.Soffset; 326 327 dt_writeToObj(objmod, dtstart, seg, offset); 328 Offset(seg) = offset; 329 Lret: 330 dt_free(dtstart); 331 } 332 333 334 /******************************************** 335 * Write dt to Object file. 336 * Params: 337 * objmod = reference to object file 338 * dt = data to write 339 * seg = segment to write it to 340 * offset = starting offset in segment - will get updated to reflect ending offset 341 */ 342 343 @trusted 344 void dt_writeToObj(Obj objmod, dt_t *dt, int seg, ref targ_size_t offset) 345 { 346 for (; dt; dt = dt.DTnext) 347 { 348 switch (dt.dt) 349 { 350 case DT_abytes: 351 { 352 int flags; 353 if (tyreg(dt.Dty)) 354 flags = CFoff; 355 else 356 flags = CFoff | CFseg; 357 if (I64) 358 flags |= CFoffset64; 359 if (tybasic(dt.Dty) == TYcptr) 360 objmod.reftocodeseg(seg,offset,dt.DTabytes); 361 else 362 { 363 if (config.exe & EX_posix) 364 { 365 objmod.reftodatseg(seg,offset,dt.DTabytes,dt.DTseg,flags); 366 } 367 else 368 { 369 if (dt.DTseg == DATA) 370 objmod.reftodatseg(seg,offset,dt.DTabytes,DATA,flags); 371 else 372 { 373 if (dt.DTseg == CDATA) 374 objmod.reftodatseg(seg,offset,dt.DTabytes,CDATA,flags); 375 else 376 objmod.reftofarseg(seg,offset,dt.DTabytes,dt.DTseg,flags); 377 } 378 } 379 } 380 offset += size(dt.Dty); 381 break; 382 } 383 384 case DT_ibytes: 385 objmod.bytes(seg,offset,dt.DTn,dt.DTdata.ptr); 386 offset += dt.DTn; 387 break; 388 389 case DT_nbytes: 390 objmod.bytes(seg,offset,dt.DTnbytes,dt.DTpbytes); 391 offset += dt.DTnbytes; 392 break; 393 394 case DT_azeros: 395 //printf("objmod.lidata(seg = %d, offset = %d, azeros = %d)\n", seg, offset, dt.DTazeros); 396 SegData[seg].SDoffset = offset; 397 objmod.lidata(seg,offset,dt.DTazeros); 398 offset = SegData[seg].SDoffset; 399 break; 400 401 case DT_xoff: 402 { 403 Symbol *sb = dt.DTsym; // get external symbol pointer 404 targ_size_t a = dt.DToffset; // offset from it 405 int flags; 406 if (tyreg(dt.Dty)) 407 flags = CFoff; 408 else 409 flags = CFoff | CFseg; 410 if (I64 && tysize(dt.Dty) == 8) 411 flags |= CFoffset64; 412 offset += objmod.reftoident(seg,offset,sb,a,flags); 413 break; 414 } 415 416 case DT_coff: 417 objmod.reftocodeseg(seg,offset,dt.DToffset); 418 offset += _tysize[TYint]; 419 break; 420 421 default: 422 //printf("dt = %p, dt = %d\n",dt,dt.dt); 423 assert(0); 424 } 425 } 426 } 427 428 429 /****************************** 430 * Output n bytes of a common block, n > 0. 431 */ 432 433 @trusted 434 void outcommon(Symbol *s,targ_size_t n) 435 { 436 //printf("outcommon('%s',%d)\n",s.Sident.ptr,n); 437 if (n != 0) 438 { 439 assert(s.Sclass == SC.global); 440 if (s.ty() & mTYcs) // if store in code segment 441 { 442 /* COMDEFs not supported in code segment 443 * so put them out as initialized 0s 444 */ 445 auto dtb = DtBuilder(0); 446 dtb.nzeros(cast(uint)n); 447 s.Sdt = dtb.finish(); 448 outdata(s); 449 } 450 else if (s.ty() & mTYthread) // if store in thread local segment 451 { 452 if (config.objfmt == OBJ_ELF) 453 { 454 s.Sclass = SC.comdef; 455 objmod.common_block(s, 0, n, 1); 456 } 457 else 458 { 459 /* COMDEFs not supported in tls segment 460 * so put them out as COMDATs with initialized 0s 461 */ 462 s.Sclass = SC.comdat; 463 auto dtb = DtBuilder(0); 464 dtb.nzeros(cast(uint)n); 465 s.Sdt = dtb.finish(); 466 outdata(s); 467 } 468 } 469 else 470 { 471 s.Sclass = SC.comdef; 472 if (config.objfmt == OBJ_OMF) 473 { 474 s.Sxtrnnum = objmod.common_block(s,(s.ty() & mTYfar) == 0,n,1); 475 if (s.ty() & mTYfar) 476 s.Sfl = FLfardata; 477 else 478 s.Sfl = FLextern; 479 s.Sseg = UNKNOWN; 480 pstate.STflags |= PFLcomdef; 481 } 482 else 483 objmod.common_block(s, 0, n, 1); 484 } 485 if (config.fulltypes) 486 { 487 if (config.objfmt == OBJ_ELF || config.objfmt == OBJ_MACH) 488 dwarf_outsym(s); 489 else 490 cv_outsym(s); 491 } 492 } 493 } 494 495 /************************************* 496 * Mark a Symbol as going into a read-only segment. 497 */ 498 499 @trusted 500 void out_readonly(Symbol *s) 501 { 502 if (config.objfmt == OBJ_ELF || config.objfmt == OBJ_MACH) 503 { 504 /* Cannot have pointers in CDATA when compiling PIC code, because 505 * they require dynamic relocations of the read-only segment. 506 * Instead use the .data.rel.ro section. 507 * https://issues.dlang.org/show_bug.cgi?id=11171 508 */ 509 if (config.flags3 & CFG3pic && dtpointers(s.Sdt)) 510 s.Sseg = CDATAREL; 511 else 512 s.Sseg = CDATA; 513 } 514 else 515 { 516 s.Sseg = CDATA; 517 } 518 } 519 520 /************************************* 521 * Write out a readonly string literal in an implementation-defined 522 * manner. 523 * Params: 524 * str = pointer to string data (need not have terminating 0) 525 * len = number of characters in string 526 * sz = size of each character (1, 2 or 4) 527 * Returns: a Symbol pointing to it. 528 */ 529 @trusted 530 Symbol *out_string_literal(const(char)* str, uint len, uint sz) 531 { 532 tym_t ty = TYchar; 533 if (sz == 2) 534 ty = TYchar16; 535 else if (sz == 4) 536 ty = TYdchar; 537 Symbol *s = symbol_generate(SC.static_,type_static_array(len, tstypes[ty])); 538 switch (config.objfmt) 539 { 540 case OBJ_ELF: 541 case OBJ_MACH: 542 s.Sseg = objmod.string_literal_segment(sz); 543 break; 544 545 case OBJ_MSCOFF: 546 case OBJ_OMF: // goes into COMDATs, handled elsewhere 547 default: 548 assert(0); 549 } 550 551 /* If there are any embedded zeros, this can't go in the special string segments 552 * which assume that 0 is the end of the string. 553 */ 554 switch (sz) 555 { 556 case 1: 557 if (memchr(str, 0, len)) 558 s.Sseg = CDATA; 559 break; 560 561 case 2: 562 foreach (i; 0 .. len) 563 { 564 auto p = cast(const(ushort)*)str; 565 if (p[i] == 0) 566 { 567 s.Sseg = CDATA; 568 break; 569 } 570 } 571 break; 572 573 case 4: 574 foreach (i; 0 .. len) 575 { 576 auto p = cast(const(uint)*)str; 577 if (p[i] == 0) 578 { 579 s.Sseg = CDATA; 580 break; 581 } 582 } 583 break; 584 585 default: 586 assert(0); 587 } 588 589 auto dtb = DtBuilder(0); 590 dtb.nbytes(cast(uint)(len * sz), str); 591 dtb.nzeros(cast(uint)sz); // include terminating 0 592 s.Sdt = dtb.finish(); 593 s.Sfl = FLdata; 594 s.Salignment = sz; 595 outdata(s); 596 return s; 597 } 598 599 600 /****************************** 601 * Walk expression tree, converting it from a PARSER tree to 602 * a code generator tree. 603 */ 604 605 @trusted 606 /*private*/ void outelem(elem *e, ref bool addressOfParam) 607 { 608 Symbol *s; 609 tym_t tym; 610 elem *e1; 611 612 again: 613 assert(e); 614 elem_debug(e); 615 616 debug 617 { 618 if (OTbinary(e.Eoper)) 619 assert(e.EV.E1 && e.EV.E2); 620 // else if (OTunary(e.Eoper)) 621 // assert(e.EV.E1 && !e.EV.E2); 622 } 623 624 switch (e.Eoper) 625 { 626 default: 627 Lop: 628 debug 629 { 630 //if (!EOP(e)) printf("e.Eoper = x%x\n",e.Eoper); 631 } 632 if (OTbinary(e.Eoper)) 633 { outelem(e.EV.E1, addressOfParam); 634 e = e.EV.E2; 635 } 636 else if (OTunary(e.Eoper)) 637 { 638 e = e.EV.E1; 639 } 640 else 641 break; 642 goto again; /* iterate instead of recurse */ 643 case OPaddr: 644 e1 = e.EV.E1; 645 if (e1.Eoper == OPvar) 646 { // Fold into an OPrelconst 647 tym = e.Ety; 648 el_copy(e,e1); 649 e.Ety = tym; 650 e.Eoper = OPrelconst; 651 el_free(e1); 652 goto again; 653 } 654 goto Lop; 655 656 case OPrelconst: 657 case OPvar: 658 s = e.EV.Vsym; 659 assert(s); 660 symbol_debug(s); 661 switch (s.Sclass) 662 { 663 case SC.regpar: 664 case SC.parameter: 665 case SC.shadowreg: 666 if (e.Eoper == OPrelconst) 667 { 668 if (I16) 669 addressOfParam = true; // taking addr of param list 670 else 671 s.Sflags &= ~(SFLunambig | GTregcand); 672 } 673 break; 674 675 case SC.static_: 676 case SC.locstat: 677 case SC.extern_: 678 case SC.global: 679 case SC.comdat: 680 case SC.comdef: 681 case SC.pseudo: 682 case SC.inline: 683 case SC.sinline: 684 case SC.einline: 685 s.Sflags |= SFLlivexit; 686 goto case; 687 case SC.auto_: 688 case SC.register: 689 case SC.fastpar: 690 case SC.bprel: 691 if (e.Eoper == OPrelconst) 692 { 693 s.Sflags &= ~(SFLunambig | GTregcand); 694 } 695 else if (s.ty() & mTYfar) 696 e.Ety |= mTYfar; 697 break; 698 default: 699 break; 700 } 701 break; 702 703 case OPstring: 704 case OPconst: 705 case OPstrthis: 706 break; 707 708 case OPsizeof: 709 assert(0); 710 711 } 712 } 713 714 /************************************* 715 * Determine register candidates. 716 */ 717 718 @trusted 719 void out_regcand(symtab_t *psymtab) 720 { 721 //printf("out_regcand()\n"); 722 const bool ifunc = (tybasic(funcsym_p.ty()) == TYifunc); 723 for (SYMIDX si = 0; si < psymtab.length; si++) 724 { Symbol *s = (*psymtab)[si]; 725 726 symbol_debug(s); 727 //assert(sytab[s.Sclass] & SCSS); // only stack variables 728 s.Ssymnum = si; // Ssymnum trashed by cpp_inlineexpand 729 if (!(s.ty() & (mTYvolatile | mTYshared)) && 730 !(ifunc && (s.Sclass == SC.parameter || s.Sclass == SC.regpar)) && 731 s.Sclass != SC.static_) 732 s.Sflags |= (GTregcand | SFLunambig); // assume register candidate 733 else 734 s.Sflags &= ~(GTregcand | SFLunambig); 735 } 736 737 bool addressOfParam = false; // haven't taken addr of param yet 738 for (block *b = startblock; b; b = b.Bnext) 739 { 740 if (b.Belem) 741 out_regcand_walk(b.Belem, addressOfParam); 742 743 // Any assembler blocks make everything ambiguous 744 if (b.BC == BCasm) 745 for (SYMIDX si = 0; si < psymtab.length; si++) 746 (*psymtab)[si].Sflags &= ~(SFLunambig | GTregcand); 747 } 748 749 // If we took the address of one parameter, assume we took the 750 // address of all non-register parameters. 751 if (addressOfParam) // if took address of a parameter 752 { 753 for (SYMIDX si = 0; si < psymtab.length; si++) 754 if ((*psymtab)[si].Sclass == SC.parameter || (*psymtab)[si].Sclass == SC.shadowreg) 755 (*psymtab)[si].Sflags &= ~(SFLunambig | GTregcand); 756 } 757 758 } 759 760 @trusted 761 private void out_regcand_walk(elem *e, ref bool addressOfParam) 762 { 763 while (1) 764 { elem_debug(e); 765 766 if (OTbinary(e.Eoper)) 767 { if (e.Eoper == OPstreq) 768 { if (e.EV.E1.Eoper == OPvar) 769 { 770 Symbol *s = e.EV.E1.EV.Vsym; 771 s.Sflags &= ~(SFLunambig | GTregcand); 772 } 773 if (e.EV.E2.Eoper == OPvar) 774 { 775 Symbol *s = e.EV.E2.EV.Vsym; 776 s.Sflags &= ~(SFLunambig | GTregcand); 777 } 778 } 779 out_regcand_walk(e.EV.E1, addressOfParam); 780 e = e.EV.E2; 781 } 782 else if (OTunary(e.Eoper)) 783 { 784 // Don't put 'this' pointers in registers if we need 785 // them for EH stack cleanup. 786 if (e.Eoper == OPctor) 787 { elem *e1 = e.EV.E1; 788 789 if (e1.Eoper == OPadd) 790 e1 = e1.EV.E1; 791 if (e1.Eoper == OPvar) 792 e1.EV.Vsym.Sflags &= ~GTregcand; 793 } 794 e = e.EV.E1; 795 } 796 else 797 { if (e.Eoper == OPrelconst) 798 { 799 Symbol *s = e.EV.Vsym; 800 assert(s); 801 symbol_debug(s); 802 switch (s.Sclass) 803 { 804 case SC.regpar: 805 case SC.parameter: 806 case SC.shadowreg: 807 if (I16) 808 addressOfParam = true; // taking addr of param list 809 else 810 s.Sflags &= ~(SFLunambig | GTregcand); 811 break; 812 813 case SC.auto_: 814 case SC.register: 815 case SC.fastpar: 816 case SC.bprel: 817 s.Sflags &= ~(SFLunambig | GTregcand); 818 break; 819 820 default: 821 break; 822 } 823 } 824 else if (e.Eoper == OPvar) 825 { 826 if (e.EV.Voffset) 827 { if (!(e.EV.Voffset == 1 && tybyte(e.Ety)) && 828 !(e.EV.Voffset == REGSIZE && tysize(e.Ety) == REGSIZE)) 829 { 830 e.EV.Vsym.Sflags &= ~GTregcand; 831 } 832 } 833 } 834 break; 835 } 836 } 837 } 838 839 840 /************************** 841 * Optimize function, 842 * generate code for it, 843 * and write it out. 844 */ 845 846 @trusted 847 void writefunc(Symbol *sfunc) 848 { 849 cstate.CSpsymtab = &globsym; 850 writefunc2(sfunc); 851 cstate.CSpsymtab = null; 852 } 853 854 @trusted 855 private void writefunc2(Symbol *sfunc) 856 { 857 func_t *f = sfunc.Sfunc; 858 859 //printf("writefunc(%s)\n",sfunc.Sident.ptr); 860 //symbol_print(sfunc); 861 debug debugy && printf("writefunc(%s)\n",sfunc.Sident.ptr); 862 863 /* Signify that function has been output */ 864 /* (before inline_do() to prevent infinite recursion!) */ 865 f.Fflags &= ~Fpending; 866 f.Fflags |= Foutput; 867 868 if (eecontext.EEcompile && eecontext.EEfunc != sfunc) 869 return; 870 871 /* Copy local symbol table onto main one, making sure */ 872 /* that the symbol numbers are adjusted accordingly */ 873 //printf("f.Flocsym.length = %d\n",f.Flocsym.length); 874 debug debugy && printf("appending symbols to symtab...\n"); 875 const nsymbols = f.Flocsym.length; 876 globsym.setLength(nsymbols); 877 foreach (si; 0 .. nsymbols) 878 globsym[si] = f.Flocsym[si]; 879 880 assert(startblock == null); 881 startblock = sfunc.Sfunc.Fstartblock; 882 sfunc.Sfunc.Fstartblock = null; 883 assert(startblock); 884 885 assert(funcsym_p == null); 886 funcsym_p = sfunc; 887 tym_t tyf = tybasic(sfunc.ty()); 888 889 // TX86 computes parameter offsets in stackoffsets() 890 //printf("globsym.length = %d\n", globsym.length); 891 892 for (SYMIDX si = 0; si < globsym.length; si++) 893 { Symbol *s = globsym[si]; 894 895 symbol_debug(s); 896 //printf("symbol %d '%s'\n",si,s.Sident.ptr); 897 898 type_size(s.Stype); // do any forward template instantiations 899 900 s.Ssymnum = si; // Ssymnum trashed by cpp_inlineexpand 901 s.Sflags &= ~(SFLunambig | GTregcand); 902 switch (s.Sclass) 903 { 904 case SC.bprel: 905 s.Sfl = FLbprel; 906 goto L3; 907 908 case SC.auto_: 909 case SC.register: 910 s.Sfl = FLauto; 911 goto L3; 912 913 case SC.fastpar: 914 s.Sfl = FLfast; 915 goto L3; 916 917 case SC.regpar: 918 case SC.parameter: 919 case SC.shadowreg: 920 s.Sfl = FLpara; 921 if (tyf == TYifunc) 922 { s.Sflags |= SFLlivexit; 923 break; 924 } 925 L3: 926 if (!(s.ty() & (mTYvolatile | mTYshared))) 927 s.Sflags |= GTregcand | SFLunambig; // assume register candidate */ 928 break; 929 930 case SC.pseudo: 931 s.Sfl = FLpseudo; 932 break; 933 934 case SC.static_: 935 break; // already taken care of by datadef() 936 937 case SC.stack: 938 s.Sfl = FLstack; 939 break; 940 941 default: 942 symbol_print(s); 943 assert(0); 944 } 945 } 946 947 bool addressOfParam = false; // see if any parameters get their address taken 948 bool anyasm = false; 949 for (block *b = startblock; b; b = b.Bnext) 950 { 951 memset(&b._BLU,0,block.sizeof - block._BLU.offsetof); 952 if (b.Belem) 953 { outelem(b.Belem, addressOfParam); 954 if (b.Belem.Eoper == OPhalt) 955 { b.BC = BCexit; 956 list_free(&b.Bsucc,FPNULL); 957 } 958 } 959 if (b.BC == BCasm) 960 anyasm = true; 961 if (sfunc.Sflags & SFLexit && (b.BC == BCret || b.BC == BCretexp)) 962 { b.BC = BCexit; 963 list_free(&b.Bsucc,FPNULL); 964 } 965 assert(b != b.Bnext); 966 } 967 PARSER = 0; 968 if (eecontext.EEelem) 969 { 970 const marksi = globsym.length; 971 eecontext.EEin++; 972 outelem(eecontext.EEelem, addressOfParam); 973 eecontext.EEelem = doptelem(eecontext.EEelem,true); 974 eecontext.EEin--; 975 eecontext_convs(marksi); 976 } 977 978 // If we took the address of one parameter, assume we took the 979 // address of all non-register parameters. 980 if (addressOfParam | anyasm) // if took address of a parameter 981 { 982 for (SYMIDX si = 0; si < globsym.length; si++) 983 if (anyasm || globsym[si].Sclass == SC.parameter) 984 globsym[si].Sflags &= ~(SFLunambig | GTregcand); 985 } 986 987 block_pred(); // compute predecessors to blocks 988 block_compbcount(); // eliminate unreachable blocks 989 990 debug { } else 991 { 992 if (debugb) 993 { 994 WRfunc("codegen", funcsym_p, startblock); 995 } 996 } 997 998 if (go.mfoptim) 999 { OPTIMIZER = 1; 1000 optfunc(); /* optimize function */ 1001 OPTIMIZER = 0; 1002 } 1003 else 1004 { 1005 //printf("blockopt()\n"); 1006 blockopt(0); /* optimize */ 1007 } 1008 1009 assert(funcsym_p == sfunc); 1010 const int CSEGSAVE_DEFAULT = -10_000; // some unlikely number 1011 int csegsave = CSEGSAVE_DEFAULT; 1012 if (eecontext.EEcompile != 1) 1013 { 1014 if (symbol_iscomdat2(sfunc)) 1015 { 1016 csegsave = cseg; 1017 objmod.comdat(sfunc); 1018 cseg = sfunc.Sseg; 1019 } 1020 else if (config.flags & CFGsegs) // if user set switch for this 1021 { 1022 objmod.codeseg(&funcsym_p.Sident[0], 1); 1023 // generate new code segment 1024 } 1025 cod3_align(cseg); // align start of function 1026 objmod.func_start(sfunc); 1027 } 1028 1029 //printf("codgen()\n"); 1030 codgen(sfunc); // generate code 1031 //printf("after codgen for %s Coffset %x\n",sfunc.Sident.ptr,Offset(cseg)); 1032 sfunc.Sfunc.Fstartblock = startblock; 1033 bool saveForInlining = canInlineFunction(sfunc); 1034 if (saveForInlining) 1035 { 1036 startblock = null; 1037 } 1038 else 1039 { 1040 sfunc.Sfunc.Fstartblock = null; 1041 blocklist_free(&startblock); 1042 } 1043 1044 objmod.func_term(sfunc); 1045 if (eecontext.EEcompile == 1) 1046 goto Ldone; 1047 if (sfunc.Sclass == SC.global) 1048 { 1049 if ((config.objfmt == OBJ_OMF || config.objfmt == OBJ_MSCOFF) && !(config.flags4 & CFG4allcomdat)) 1050 { 1051 assert(sfunc.Sseg == cseg); 1052 objmod.pubdef(sfunc.Sseg,sfunc,sfunc.Soffset); // make a public definition 1053 } 1054 1055 addStartupReference(sfunc); 1056 } 1057 1058 if (config.wflags & WFexpdef && 1059 sfunc.Sclass != SC.static_ && 1060 sfunc.Sclass != SC.sinline && 1061 !(sfunc.Sclass == SC.inline && !(config.flags2 & CFG2comdat)) && 1062 sfunc.ty() & mTYexport) 1063 objmod.export_symbol(sfunc,cast(uint)Para.offset); // export function definition 1064 1065 if (config.fulltypes && config.fulltypes != CV8) 1066 { 1067 if (config.objfmt == OBJ_OMF || config.objfmt == OBJ_MSCOFF) 1068 cv_func(sfunc); // debug info for function 1069 } 1070 1071 /* This is to make uplevel references to SCfastpar variables 1072 * from nested functions work. 1073 */ 1074 for (SYMIDX si = 0; si < globsym.length; si++) 1075 { 1076 Symbol *s = globsym[si]; 1077 1078 switch (s.Sclass) 1079 { case SC.fastpar: 1080 s.Sclass = SC.auto_; 1081 break; 1082 1083 default: 1084 break; 1085 } 1086 } 1087 /* After codgen() and writing debug info for the locals, 1088 * readjust the offsets of all stack variables so they 1089 * are relative to the frame pointer. 1090 * Necessary for nested function access to lexically enclosing frames. 1091 */ 1092 cod3_adjSymOffsets(); 1093 1094 if (symbol_iscomdat2(sfunc)) // if generated a COMDAT 1095 { 1096 assert(csegsave != CSEGSAVE_DEFAULT); 1097 objmod.setcodeseg(csegsave); // reset to real code seg 1098 if (config.objfmt == OBJ_MACH) 1099 assert(cseg == CODE); 1100 } 1101 1102 /* Check if function is a constructor or destructor, by */ 1103 /* seeing if the function name starts with _STI or _STD */ 1104 { 1105 version (LittleEndian) 1106 { 1107 short *p = cast(short *) sfunc.Sident.ptr; 1108 if (p[0] == (('S' << 8) | '_') && (p[1] == (('I' << 8) | 'T') || p[1] == (('D' << 8) | 'T'))) 1109 objmod.setModuleCtorDtor(sfunc, sfunc.Sident.ptr[3] == 'I'); 1110 } 1111 else 1112 { 1113 char *p = sfunc.Sident.ptr; 1114 if (p[0] == '_' && p[1] == 'S' && p[2] == 'T' && 1115 (p[3] == 'I' || p[3] == 'D')) 1116 objmod.setModuleCtorDtor(sfunc, sfunc.Sident.ptr[3] == 'I'); 1117 } 1118 } 1119 1120 Ldone: 1121 funcsym_p = null; 1122 1123 if (saveForInlining) 1124 { 1125 f.Flocsym.setLength(globsym.length); 1126 foreach (si; 0 .. globsym.length) 1127 f.Flocsym[si] = globsym[si]; 1128 } 1129 else 1130 { 1131 } 1132 globsym.setLength(0); 1133 1134 //printf("done with writefunc()\n"); 1135 //dfo.dtor(); // save allocation for next time 1136 } 1137 1138 /************************* 1139 * Align segment offset. 1140 * Input: 1141 * seg segment to be aligned 1142 * datasize size in bytes of object to be aligned 1143 */ 1144 1145 @trusted 1146 void alignOffset(int seg,targ_size_t datasize) 1147 { 1148 targ_size_t alignbytes = _align(datasize,Offset(seg)) - Offset(seg); 1149 //printf("seg %d datasize = x%x, Offset(seg) = x%x, alignbytes = x%x\n", 1150 //seg,datasize,Offset(seg),alignbytes); 1151 if (alignbytes) 1152 objmod.lidata(seg,Offset(seg),alignbytes); 1153 } 1154 1155 /*************************************** 1156 * Write data into read-only data segment. 1157 * Return symbol for it. 1158 */ 1159 1160 enum ROMAX = 32; 1161 struct Readonly 1162 { 1163 Symbol *sym; 1164 size_t length; 1165 ubyte[ROMAX] p; 1166 } 1167 1168 enum RMAX = 16; 1169 private __gshared 1170 { 1171 Readonly[RMAX] readonly; 1172 size_t readonly_length; 1173 size_t readonly_i; 1174 } 1175 1176 @trusted 1177 void out_reset() 1178 { 1179 readonly_length = 0; 1180 readonly_i = 0; 1181 } 1182 1183 @trusted 1184 Symbol *out_readonly_sym(tym_t ty, void *p, int len) 1185 { 1186 static if (0) 1187 { 1188 printf("out_readonly_sym(ty = x%x)\n", ty); 1189 for (int i = 0; i < len; i++) 1190 printf(" [%d] = %02x\n", i, (cast(ubyte*)p)[i]); 1191 } 1192 // Look for previous symbol we can reuse 1193 for (int i = 0; i < readonly_length; i++) 1194 { 1195 Readonly *r = &readonly[i]; 1196 if (r.length == len && memcmp(p, r.p.ptr, len) == 0) 1197 return r.sym; 1198 } 1199 1200 Symbol *s; 1201 1202 bool cdata = config.objfmt == OBJ_ELF || 1203 config.objfmt == OBJ_OMF || 1204 config.objfmt == OBJ_MSCOFF; 1205 if (cdata) 1206 { 1207 /* MACHOBJ can't go here, because the const data segment goes into 1208 * the _TEXT segment, and one cannot have a fixup from _TEXT to _TEXT. 1209 */ 1210 s = objmod.sym_cdata(ty, cast(char *)p, len); 1211 } 1212 else 1213 { 1214 uint sz = tysize(ty); 1215 1216 alignOffset(DATA, sz); 1217 s = symboldata(Offset(DATA),ty | mTYconst); 1218 s.Sseg = DATA; 1219 objmod.write_bytes(SegData[DATA], p[0 .. len]); 1220 //printf("s.Sseg = %d:x%x\n", s.Sseg, s.Soffset); 1221 } 1222 1223 if (len <= ROMAX) 1224 { Readonly *r; 1225 1226 if (readonly_length < RMAX) 1227 { 1228 r = &readonly[readonly_length]; 1229 readonly_length++; 1230 } 1231 else 1232 { r = &readonly[readonly_i]; 1233 readonly_i++; 1234 if (readonly_i >= RMAX) 1235 readonly_i = 0; 1236 } 1237 r.length = len; 1238 r.sym = s; 1239 memcpy(r.p.ptr, p, len); 1240 } 1241 return s; 1242 } 1243 1244 /************************************* 1245 * Output Symbol as a readonly comdat. 1246 * Params: 1247 * s = comdat symbol 1248 * p = pointer to the data to write 1249 * len = length of that data 1250 * nzeros = number of trailing zeros to append 1251 */ 1252 @trusted 1253 void out_readonly_comdat(Symbol *s, const(void)* p, uint len, uint nzeros) 1254 { 1255 objmod.readonly_comdat(s); // create comdat segment 1256 objmod.write_bytes(SegData[s.Sseg], p[0 .. len]); 1257 objmod.lidata(s.Sseg, len, nzeros); 1258 } 1259 1260 @trusted 1261 void Srcpos_print(ref const Srcpos srcpos, const(char)* func) 1262 { 1263 printf("%s(", func); 1264 printf("Sfilename = %s", srcpos.Sfilename ? srcpos.Sfilename : "null".ptr); 1265 printf(", Slinnum = %u", srcpos.Slinnum); 1266 printf(")\n"); 1267 } 1268 1269 /********************************************* 1270 * If sfunc is the entry point, add a reference to pull 1271 * in the startup code. 1272 * Params: 1273 * sfunc = function 1274 */ 1275 private 1276 @trusted 1277 void addStartupReference(Symbol* sfunc) 1278 { 1279 }