1 /** 2 * Converts expressions to Intermediate Representation (IR) for the backend. 3 * 4 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/e2ir.d, _e2ir.d) 8 * Documentation: https://dlang.org/phobos/dmd_e2ir.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/e2ir.d 10 */ 11 12 module dmd.e2ir; 13 14 import core.stdc.stdio; 15 import core.stdc.stddef; 16 import core.stdc..string; 17 import core.stdc.time; 18 19 import dmd.root.array; 20 import dmd.root.ctfloat; 21 import dmd.root.rmem; 22 import dmd.root.rootobject; 23 import dmd.root.stringtable; 24 25 import dmd.aggregate; 26 import dmd.arraytypes; 27 import dmd.attrib; 28 import dmd.canthrow; 29 import dmd.ctfeexpr; 30 import dmd.dclass; 31 import dmd.declaration; 32 import dmd.denum; 33 import dmd.dmodule; 34 import dmd.dscope; 35 import dmd.dstruct; 36 import dmd.dsymbol; 37 import dmd.dtemplate; 38 import dmd.errors; 39 import dmd.expression; 40 import dmd.func; 41 import dmd.globals; 42 import dmd.glue; 43 import dmd.id; 44 import dmd.init; 45 import dmd.mtype; 46 import dmd.objc_glue; 47 import dmd.s2ir; 48 import dmd.sideeffect; 49 import dmd.statement; 50 import dmd.target; 51 import dmd.tocsym; 52 import dmd.toctype; 53 import dmd.toir; 54 import dmd.tokens; 55 import dmd.toobj; 56 import dmd.typinf; 57 import dmd.visitor; 58 59 import dmd.backend.cc; 60 import dmd.backend.cdef; 61 import dmd.backend.cgcv; 62 import dmd.backend.code; 63 import dmd.backend.code_x86; 64 import dmd.backend.cv4; 65 import dmd.backend.dt; 66 import dmd.backend.el; 67 import dmd.backend.global; 68 import dmd.backend.obj; 69 import dmd.backend.oper; 70 import dmd.backend.rtlsym; 71 import dmd.backend.ty; 72 import dmd.backend.type; 73 74 extern (C++): 75 76 alias Elems = Array!(elem *); 77 78 alias toSymbol = dmd.tocsym.toSymbol; 79 alias toSymbol = dmd.glue.toSymbol; 80 81 void* mem_malloc2(uint); 82 83 84 @property int REGSIZE() { return _tysize[TYnptr]; } 85 86 /* If variable var is a reference 87 */ 88 bool ISREF(Declaration var) 89 { 90 if (var.isOut() || var.isRef()) 91 { 92 return true; 93 } 94 95 return ISX64REF(var); 96 } 97 98 /* If variable var of type typ is a reference due to x64 calling conventions 99 */ 100 bool ISX64REF(Declaration var) 101 { 102 if (var.isOut() || var.isRef()) 103 { 104 return false; 105 } 106 107 if (var.isParameter()) 108 { 109 if (config.exe == EX_WIN64) 110 { 111 return var.type.size(Loc.initial) > REGSIZE 112 || (var.storage_class & STC.lazy_) 113 || (var.type.isTypeStruct() && !var.type.isTypeStruct().sym.isPOD()); 114 } 115 else if (!global.params.isWindows) 116 { 117 return !(var.storage_class & STC.lazy_) && var.type.isTypeStruct() && !var.type.isTypeStruct().sym.isPOD(); 118 } 119 } 120 121 return false; 122 } 123 124 /* If variable exp of type typ is a reference due to x64 calling conventions 125 */ 126 bool ISX64REF(IRState* irs, Expression exp) 127 { 128 if (config.exe == EX_WIN64) 129 { 130 return exp.type.size(Loc.initial) > REGSIZE 131 || (exp.type.isTypeStruct() && !exp.type.isTypeStruct().sym.isPOD()); 132 } 133 else if (!irs.params.isWindows) 134 { 135 return exp.type.isTypeStruct() && !exp.type.isTypeStruct().sym.isPOD(); 136 } 137 138 return false; 139 } 140 141 /****************************************** 142 * If argument to a function should use OPstrpar, 143 * fix it so it does and return it. 144 */ 145 private elem *useOPstrpar(elem *e) 146 { 147 tym_t ty = tybasic(e.Ety); 148 if (ty == TYstruct || ty == TYarray) 149 { 150 e = el_una(OPstrpar, TYstruct, e); 151 e.ET = e.EV.E1.ET; 152 assert(e.ET); 153 } 154 return e; 155 } 156 157 /************************************ 158 * Call a function. 159 */ 160 161 private elem *callfunc(const ref Loc loc, 162 IRState *irs, 163 int directcall, // 1: don't do virtual call 164 Type tret, // return type 165 elem *ec, // evaluates to function address 166 Type ectype, // original type of ec 167 FuncDeclaration fd, // if !=NULL, this is the function being called 168 Type t, // TypeDelegate or TypeFunction for this function 169 elem *ehidden, // if !=null, this is the 'hidden' argument 170 Expressions *arguments, 171 elem *esel = null, // selector for Objective-C methods (when not provided by fd) 172 elem *ethis2 = null) // multi-context array 173 { 174 elem *ethis = null; 175 elem *eside = null; 176 elem *eresult = ehidden; 177 178 version (none) 179 { 180 printf("callfunc(directcall = %d, tret = '%s', ec = %p, fd = %p)\n", 181 directcall, tret.toChars(), ec, fd); 182 printf("ec: "); elem_print(ec); 183 if (fd) 184 printf("fd = '%s', vtblIndex = %d, isVirtual() = %d\n", fd.toChars(), fd.vtblIndex, fd.isVirtual()); 185 if (ehidden) 186 { printf("ehidden: "); elem_print(ehidden); } 187 } 188 189 t = t.toBasetype(); 190 TypeFunction tf = t.isTypeFunction(); 191 if (!tf) 192 { 193 assert(t.ty == Tdelegate); 194 // A delegate consists of: 195 // { Object *this; Function *funcptr; } 196 assert(!fd); 197 tf = t.nextOf().isTypeFunction(); 198 assert(tf); 199 ethis = ec; 200 ec = el_same(ðis); 201 ethis = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYnptr, ethis); // get this 202 ec = array_toPtr(t, ec); // get funcptr 203 ec = el_una(OPind, totym(tf), ec); 204 } 205 206 const ty = fd ? toSymbol(fd).Stype.Tty : ec.Ety; 207 const left_to_right = tyrevfunc(ty); // left-to-right parameter evaluation 208 // (TYnpfunc, TYjfunc, TYfpfunc, TYf16func) 209 elem* ep = null; 210 const op = fd ? intrinsic_op(fd) : NotIntrinsic; 211 if (arguments && arguments.dim) 212 { 213 if (op == OPvector) 214 { 215 Expression arg = (*arguments)[0]; 216 if (arg.op != TOK.int64) 217 arg.error("simd operator must be an integer constant, not `%s`", arg.toChars()); 218 } 219 220 /* Convert arguments[] to elems[] in left-to-right order 221 */ 222 const n = arguments.dim; 223 debug 224 elem*[2] elems_array = void; 225 else 226 elem*[10] elems_array = void; 227 import core.stdc.stdlib : malloc, free; 228 auto pe = (n <= elems_array.length) 229 ? elems_array.ptr 230 : cast(elem**)Mem.check(malloc(arguments.dim * (elem*).sizeof)); 231 elem*[] elems = pe[0 .. n]; 232 233 /* Fill elems[] with arguments converted to elems 234 */ 235 236 // j=1 if _arguments[] is first argument 237 const int j = tf.isDstyleVariadic(); 238 239 foreach (const i, arg; *arguments) 240 { 241 elem *ea = toElem(arg, irs); 242 243 //printf("\targ[%d]: %s\n", i, arg.toChars()); 244 245 if (i - j < tf.parameterList.length && 246 i >= j && 247 tf.parameterList[i - j].storageClass & (STC.out_ | STC.ref_)) 248 { 249 /* `ref` and `out` parameters mean convert 250 * corresponding argument to a pointer 251 */ 252 elems[i] = addressElem(ea, arg.type.pointerTo()); 253 continue; 254 } 255 256 if (ISX64REF(irs, arg) && op == NotIntrinsic) 257 { 258 /* Copy to a temporary, and make the argument a pointer 259 * to that temporary. 260 */ 261 elems[i] = addressElem(ea, arg.type, true); 262 continue; 263 } 264 265 if (config.exe == EX_WIN64 && tybasic(ea.Ety) == TYcfloat) 266 { 267 /* Treat a cfloat like it was a struct { float re,im; } 268 */ 269 ea.Ety = TYllong; 270 } 271 elems[i] = ea; 272 } 273 if (!left_to_right) 274 { 275 /* Avoid 'fixing' side effects of _array... functions as 276 * they were already working right from the olden days before this fix 277 */ 278 if (!(ec.Eoper == OPvar && fd.isArrayOp)) 279 eside = fixArgumentEvaluationOrder(elems); 280 } 281 282 foreach (ref e; elems) 283 { 284 e = useOPstrpar(e); 285 } 286 287 if (!left_to_right) // swap order if right-to-left 288 reverse(elems); 289 290 ep = el_params(cast(void**)elems.ptr, cast(int)n); 291 292 if (elems.ptr != elems_array.ptr) 293 free(elems.ptr); 294 } 295 296 objc.setupMethodSelector(fd, &esel); 297 objc.setupEp(esel, &ep, left_to_right); 298 299 const retmethod = retStyle(tf, fd && fd.needThis()); 300 if (retmethod == RET.stack) 301 { 302 if (!ehidden) 303 { 304 // Don't have one, so create one 305 type *tc; 306 307 Type tret2 = tf.next; 308 if (tret2.toBasetype().ty == Tstruct || 309 tret2.toBasetype().ty == Tsarray) 310 tc = Type_toCtype(tret2); 311 else 312 tc = type_fake(totym(tret2)); 313 Symbol *stmp = symbol_genauto(tc); 314 ehidden = el_ptr(stmp); 315 eresult = ehidden; 316 } 317 if (target.isPOSIX && tf.linkage != LINK.d) 318 { 319 // ehidden goes last on Linux/OSX C++ 320 } 321 else 322 { 323 if (ep) 324 { 325 /* // BUG: implement 326 if (left_to_right && type_mangle(tfunc) == mTYman_cpp) 327 ep = el_param(ehidden,ep); 328 else 329 */ 330 ep = el_param(ep,ehidden); 331 } 332 else 333 ep = ehidden; 334 ehidden = null; 335 } 336 } 337 338 if (fd && fd.isMemberLocal()) 339 { 340 assert(op == NotIntrinsic); // members should not be intrinsics 341 342 AggregateDeclaration ad = fd.isThis(); 343 if (ad) 344 { 345 ethis = ec; 346 if (ad.isStructDeclaration() && tybasic(ec.Ety) != TYnptr) 347 { 348 ethis = addressElem(ec, ectype); 349 } 350 if (ethis2) 351 { 352 ethis2 = setEthis2(loc, irs, fd, ethis2, ðis, &eside); 353 } 354 if (el_sideeffect(ethis)) 355 { 356 elem *ex = ethis; 357 ethis = el_copytotmp(&ex); 358 eside = el_combine(ex, eside); 359 } 360 } 361 else 362 { 363 // Evaluate ec for side effects 364 eside = el_combine(ec, eside); 365 } 366 Symbol *sfunc = toSymbol(fd); 367 368 if (esel) 369 { 370 auto result = objc.setupMethodCall(fd, tf, directcall != 0, ec, ehidden, ethis); 371 ec = result.ec; 372 ethis = result.ethis; 373 } 374 else if (!fd.isVirtual() || 375 directcall || // BUG: fix 376 fd.isFinalFunc() 377 /* Future optimization: || (whole program analysis && not overridden) 378 */ 379 ) 380 { 381 // make static call 382 ec = el_var(sfunc); 383 } 384 else 385 { 386 // make virtual call 387 assert(ethis); 388 elem *ev = el_same(ðis); 389 ev = el_una(OPind, TYnptr, ev); 390 uint vindex = fd.vtblIndex; 391 assert(cast(int)vindex >= 0); 392 393 // Build *(ev + vindex * 4) 394 if (!irs.params.is64bit) assert(tysize(TYnptr) == 4); 395 ec = el_bin(OPadd,TYnptr,ev,el_long(TYsize_t, vindex * tysize(TYnptr))); 396 ec = el_una(OPind,TYnptr,ec); 397 ec = el_una(OPind,tybasic(sfunc.Stype.Tty),ec); 398 } 399 } 400 else if (fd && fd.isNested()) 401 { 402 assert(!ethis); 403 ethis = getEthis(loc, irs, fd, fd.toParentLocal()); 404 if (ethis2) 405 ethis2 = setEthis2(loc, irs, fd, ethis2, ðis, &eside); 406 } 407 408 ep = el_param(ep, ethis2 ? ethis2 : ethis); 409 if (ehidden) 410 ep = el_param(ep, ehidden); // if ehidden goes last 411 412 const tyret = totym(tret); 413 414 // Look for intrinsic functions and construct result into e 415 elem *e; 416 if (ec.Eoper == OPvar && op != NotIntrinsic) 417 { 418 el_free(ec); 419 if (op != OPtoPrec && OTbinary(op)) 420 { 421 ep.Eoper = cast(ubyte)op; 422 ep.Ety = tyret; 423 e = ep; 424 if (op == OPeq) 425 { /* This was a volatileStore(ptr, value) operation, rewrite as: 426 * *ptr = value 427 */ 428 e.EV.E1 = el_una(OPind, e.EV.E2.Ety | mTYvolatile, e.EV.E1); 429 } 430 if (op == OPscale) 431 { 432 elem *et = e.EV.E1; 433 e.EV.E1 = el_una(OPs32_d, TYdouble, e.EV.E2); 434 e.EV.E1 = el_una(OPd_ld, TYldouble, e.EV.E1); 435 e.EV.E2 = et; 436 } 437 else if (op == OPyl2x || op == OPyl2xp1) 438 { 439 elem *et = e.EV.E1; 440 e.EV.E1 = e.EV.E2; 441 e.EV.E2 = et; 442 } 443 } 444 else if (op == OPvector) 445 { 446 e = ep; 447 /* Recognize store operations as: 448 * (op OPparam (op1 OPparam op2)) 449 * Rewrite as: 450 * (op1 OPvecsto (op OPparam op2)) 451 * A separate operation is used for stores because it 452 * has a side effect, and so takes a different path through 453 * the optimizer. 454 */ 455 if (e.Eoper == OPparam && 456 e.EV.E1.Eoper == OPconst && 457 isXMMstore(cast(uint)el_tolong(e.EV.E1))) 458 { 459 //printf("OPvecsto\n"); 460 elem *tmp = e.EV.E1; 461 e.EV.E1 = e.EV.E2.EV.E1; 462 e.EV.E2.EV.E1 = tmp; 463 e.Eoper = OPvecsto; 464 e.Ety = tyret; 465 } 466 else 467 e = el_una(op,tyret,ep); 468 } 469 else if (op == OPind) 470 e = el_una(op,mTYvolatile | tyret,ep); 471 else if (op == OPva_start && irs.params.is64bit) 472 { 473 // (OPparam &va &arg) 474 // call as (OPva_start &va) 475 ep.Eoper = cast(ubyte)op; 476 ep.Ety = tyret; 477 e = ep; 478 479 elem *earg = e.EV.E2; 480 e.EV.E2 = null; 481 e = el_combine(earg, e); 482 } 483 else if (op == OPtoPrec) 484 { 485 static int X(int fty, int tty) { return fty * TMAX + tty; } 486 487 final switch (X(tybasic(ep.Ety), tybasic(tyret))) 488 { 489 case X(TYfloat, TYfloat): // float -> float 490 case X(TYdouble, TYdouble): // double -> double 491 case X(TYldouble, TYldouble): // real -> real 492 e = ep; 493 break; 494 495 case X(TYfloat, TYdouble): // float -> double 496 e = el_una(OPf_d, tyret, ep); 497 break; 498 499 case X(TYfloat, TYldouble): // float -> real 500 e = el_una(OPf_d, TYdouble, ep); 501 e = el_una(OPd_ld, tyret, e); 502 break; 503 504 case X(TYdouble, TYfloat): // double -> float 505 e = el_una(OPd_f, tyret, ep); 506 break; 507 508 case X(TYdouble, TYldouble): // double -> real 509 e = el_una(OPd_ld, tyret, ep); 510 break; 511 512 case X(TYldouble, TYfloat): // real -> float 513 e = el_una(OPld_d, TYdouble, ep); 514 e = el_una(OPd_f, tyret, e); 515 break; 516 517 case X(TYldouble, TYdouble): // real -> double 518 e = el_una(OPld_d, tyret, ep); 519 break; 520 } 521 } 522 else 523 e = el_una(op,tyret,ep); 524 } 525 else 526 { 527 /* Do not do "no side effect" calls if a hidden parameter is passed, 528 * as the return value is stored through the hidden parameter, which 529 * is a side effect. 530 */ 531 //printf("1: fd = %p prity = %d, nothrow = %d, retmethod = %d, use-assert = %d\n", 532 // fd, (fd ? fd.isPure() : tf.purity), tf.isnothrow, retmethod, irs.params.useAssert); 533 //printf("\tfd = %s, tf = %s\n", fd.toChars(), tf.toChars()); 534 /* assert() has 'implicit side effect' so disable this optimization. 535 */ 536 int ns = ((fd ? callSideEffectLevel(fd) 537 : callSideEffectLevel(t)) == 2 && 538 retmethod != RET.stack && 539 irs.params.useAssert == CHECKENABLE.off && irs.params.optimize); 540 if (ep) 541 e = el_bin(ns ? OPcallns : OPcall, tyret, ec, ep); 542 else 543 e = el_una(ns ? OPucallns : OPucall, tyret, ec); 544 545 if (tf.parameterList.varargs != VarArg.none) 546 e.Eflags |= EFLAGS_variadic; 547 } 548 549 const isCPPCtor = fd && fd.linkage == LINK.cpp && fd.isCtorDeclaration(); 550 if (isCPPCtor && target.isPOSIX) 551 { 552 // CPP constructor returns void on Posix 553 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#return-value-ctor 554 e.Ety = TYvoid; 555 e = el_combine(e, el_same(ðis)); 556 } 557 else if (retmethod == RET.stack) 558 { 559 if (irs.params.isOSX && eresult) 560 /* ABI quirk: hidden pointer is not returned in registers 561 */ 562 e = el_combine(e, el_copytree(eresult)); 563 e.Ety = TYnptr; 564 e = el_una(OPind, tyret, e); 565 } 566 567 if (tf.isref) 568 { 569 e.Ety = TYnptr; 570 e = el_una(OPind, tyret, e); 571 } 572 573 if (tybasic(tyret) == TYstruct) 574 { 575 e.ET = Type_toCtype(tret); 576 } 577 e = el_combine(eside, e); 578 return e; 579 } 580 581 /********************************** 582 * D presumes left-to-right argument evaluation, but we're evaluating things 583 * right-to-left here. 584 * 1. determine if this matters 585 * 2. fix it if it does 586 * Params: 587 * arguments = function arguments, these will get rewritten in place 588 * Returns: 589 * elem that evaluates the side effects 590 */ 591 private extern (D) elem *fixArgumentEvaluationOrder(elem*[] elems) 592 { 593 /* It matters if all are true: 594 * 1. at least one argument has side effects 595 * 2. at least one other argument may depend on side effects 596 */ 597 if (elems.length <= 1) 598 return null; 599 600 size_t ifirstside = 0; // index-1 of first side effect 601 size_t ifirstdep = 0; // index-1 of first dependency on side effect 602 foreach (i, e; elems) 603 { 604 switch (e.Eoper) 605 { 606 case OPconst: 607 case OPrelconst: 608 case OPstring: 609 continue; 610 611 default: 612 break; 613 } 614 615 if (el_sideeffect(e)) 616 { 617 if (!ifirstside) 618 ifirstside = i + 1; 619 else if (!ifirstdep) 620 ifirstdep = i + 1; 621 } 622 else 623 { 624 if (!ifirstdep) 625 ifirstdep = i + 1; 626 } 627 if (ifirstside && ifirstdep) 628 break; 629 } 630 631 if (!ifirstdep || !ifirstside) 632 return null; 633 634 /* Now fix by appending side effects and dependencies to eside and replacing 635 * argument with a temporary. 636 * Rely on the optimizer removing some unneeded ones using flow analysis. 637 */ 638 elem* eside = null; 639 foreach (i, e; elems) 640 { 641 while (e.Eoper == OPcomma) 642 { 643 eside = el_combine(eside, e.EV.E1); 644 e = e.EV.E2; 645 elems[i] = e; 646 } 647 648 switch (e.Eoper) 649 { 650 case OPconst: 651 case OPrelconst: 652 case OPstring: 653 continue; 654 655 default: 656 break; 657 } 658 659 elem *es = e; 660 elems[i] = el_copytotmp(&es); 661 eside = el_combine(eside, es); 662 } 663 664 return eside; 665 } 666 667 /******************************************* 668 * Take address of an elem. 669 */ 670 671 elem *addressElem(elem *e, Type t, bool alwaysCopy = false) 672 { 673 //printf("addressElem()\n"); 674 675 elem **pe; 676 for (pe = &e; (*pe).Eoper == OPcomma; pe = &(*pe).EV.E2) 677 { 678 } 679 680 // For conditional operator, both branches need conversion. 681 if ((*pe).Eoper == OPcond) 682 { 683 elem *ec = (*pe).EV.E2; 684 685 ec.EV.E1 = addressElem(ec.EV.E1, t, alwaysCopy); 686 ec.EV.E2 = addressElem(ec.EV.E2, t, alwaysCopy); 687 688 (*pe).Ejty = (*pe).Ety = cast(ubyte)ec.EV.E1.Ety; 689 (*pe).ET = ec.EV.E1.ET; 690 691 e.Ety = TYnptr; 692 return e; 693 } 694 695 if (alwaysCopy || ((*pe).Eoper != OPvar && (*pe).Eoper != OPind)) 696 { 697 elem *e2 = *pe; 698 type *tx; 699 700 // Convert to ((tmp=e2),tmp) 701 TY ty; 702 if (t && ((ty = t.toBasetype().ty) == Tstruct || ty == Tsarray)) 703 tx = Type_toCtype(t); 704 else if (tybasic(e2.Ety) == TYstruct) 705 { 706 assert(t); // don't know of a case where this can be null 707 tx = Type_toCtype(t); 708 } 709 else 710 tx = type_fake(e2.Ety); 711 Symbol *stmp = symbol_genauto(tx); 712 713 elem *eeq = elAssign(el_var(stmp), e2, t, tx); 714 *pe = el_bin(OPcomma,e2.Ety,eeq,el_var(stmp)); 715 } 716 tym_t typ = TYnptr; 717 if (e.Eoper == OPind && tybasic(e.EV.E1.Ety) == TYimmutPtr) 718 typ = TYimmutPtr; 719 e = el_una(OPaddr,typ,e); 720 return e; 721 } 722 723 /*************************************** 724 * Return `true` if elem is a an lvalue. 725 * Lvalue elems are OPvar and OPind. 726 */ 727 728 bool elemIsLvalue(elem* e) 729 { 730 while (e.Eoper == OPcomma || e.Eoper == OPinfo) 731 e = e.EV.E2; 732 733 // For conditional operator, both branches need to be lvalues. 734 if (e.Eoper == OPcond) 735 { 736 elem* ec = e.EV.E2; 737 return elemIsLvalue(ec.EV.E1) && elemIsLvalue(ec.EV.E2); 738 } 739 740 return e.Eoper == OPvar || e.Eoper == OPind; 741 } 742 743 /***************************************** 744 * Convert array to a pointer to the data. 745 * Params: 746 * t = array type 747 * e = array to convert, it is "consumed" by the function 748 * Returns: 749 * e rebuilt into a pointer to the data 750 */ 751 752 elem *array_toPtr(Type t, elem *e) 753 { 754 //printf("array_toPtr()\n"); 755 //elem_print(e); 756 t = t.toBasetype(); 757 switch (t.ty) 758 { 759 case Tpointer: 760 break; 761 762 case Tarray: 763 case Tdelegate: 764 if (e.Eoper == OPcomma) 765 { 766 e.Ety = TYnptr; 767 e.EV.E2 = array_toPtr(t, e.EV.E2); 768 } 769 else if (e.Eoper == OPpair) 770 { 771 if (el_sideeffect(e.EV.E1)) 772 { 773 e.Eoper = OPcomma; 774 e.Ety = TYnptr; 775 } 776 else 777 { 778 auto r = e; 779 e = e.EV.E2; 780 e.Ety = TYnptr; 781 r.EV.E2 = null; 782 el_free(r); 783 } 784 } 785 else 786 { 787 version (all) 788 e = el_una(OPmsw, TYnptr, e); 789 else 790 { 791 e = el_una(OPaddr, TYnptr, e); 792 e = el_bin(OPadd, TYnptr, e, el_long(TYsize_t, 4)); 793 e = el_una(OPind, TYnptr, e); 794 } 795 } 796 break; 797 798 case Tsarray: 799 //e = el_una(OPaddr, TYnptr, e); 800 e = addressElem(e, t); 801 break; 802 803 default: 804 printf("%s\n", t.toChars()); 805 assert(0); 806 } 807 return e; 808 } 809 810 /***************************************** 811 * Convert array to a dynamic array. 812 */ 813 814 elem *array_toDarray(Type t, elem *e) 815 { 816 uint dim; 817 elem *ef = null; 818 elem *ex; 819 820 //printf("array_toDarray(t = %s)\n", t.toChars()); 821 //elem_print(e); 822 t = t.toBasetype(); 823 switch (t.ty) 824 { 825 case Tarray: 826 break; 827 828 case Tsarray: 829 e = addressElem(e, t); 830 dim = cast(uint)(cast(TypeSArray)t).dim.toInteger(); 831 e = el_pair(TYdarray, el_long(TYsize_t, dim), e); 832 break; 833 834 default: 835 L1: 836 switch (e.Eoper) 837 { 838 case OPconst: 839 { 840 size_t len = tysize(e.Ety); 841 elem *es = el_calloc(); 842 es.Eoper = OPstring; 843 844 // freed in el_free 845 es.EV.Vstring = cast(char*)mem_malloc2(cast(uint)len); 846 memcpy(es.EV.Vstring, &e.EV, len); 847 848 es.EV.Vstrlen = len; 849 es.Ety = TYnptr; 850 e = es; 851 break; 852 } 853 854 case OPvar: 855 e = el_una(OPaddr, TYnptr, e); 856 break; 857 858 case OPcomma: 859 ef = el_combine(ef, e.EV.E1); 860 ex = e; 861 e = e.EV.E2; 862 ex.EV.E1 = null; 863 ex.EV.E2 = null; 864 el_free(ex); 865 goto L1; 866 867 case OPind: 868 ex = e; 869 e = e.EV.E1; 870 ex.EV.E1 = null; 871 ex.EV.E2 = null; 872 el_free(ex); 873 break; 874 875 default: 876 { 877 // Copy expression to a variable and take the 878 // address of that variable. 879 e = addressElem(e, t); 880 break; 881 } 882 } 883 dim = 1; 884 e = el_pair(TYdarray, el_long(TYsize_t, dim), e); 885 break; 886 } 887 return el_combine(ef, e); 888 } 889 890 /************************************ 891 */ 892 893 elem *sarray_toDarray(const ref Loc loc, Type tfrom, Type tto, elem *e) 894 { 895 //printf("sarray_toDarray()\n"); 896 //elem_print(e); 897 898 dinteger_t dim = (cast(TypeSArray)tfrom).dim.toInteger(); 899 900 if (tto) 901 { 902 uint fsize = cast(uint)tfrom.nextOf().size(); 903 uint tsize = cast(uint)tto.nextOf().size(); 904 905 if ((dim * fsize) % tsize != 0) 906 { 907 // have to change to Internal Compiler Error? 908 error(loc, "cannot cast %s to %s since sizes don't line up", tfrom.toChars(), tto.toChars()); 909 } 910 dim = (dim * fsize) / tsize; 911 } 912 elem *elen = el_long(TYsize_t, dim); 913 e = addressElem(e, tfrom); 914 e = el_pair(TYdarray, elen, e); 915 return e; 916 } 917 918 /************************************ 919 */ 920 921 elem *getTypeInfo(Loc loc, Type t, IRState *irs) 922 { 923 assert(t.ty != Terror); 924 genTypeInfo(loc, t, null); 925 elem *e = el_ptr(toSymbol(t.vtinfo)); 926 return e; 927 } 928 929 /******************************************** 930 * Determine if t is a struct that has postblit. 931 */ 932 StructDeclaration needsPostblit(Type t) 933 { 934 if (auto ts = t.baseElemOf().isTypeStruct()) 935 { 936 StructDeclaration sd = ts.sym; 937 if (sd.postblit) 938 return sd; 939 } 940 return null; 941 } 942 943 /******************************************** 944 * Determine if t is a struct that has destructor. 945 */ 946 StructDeclaration needsDtor(Type t) 947 { 948 if (auto ts = t.baseElemOf().isTypeStruct()) 949 { 950 StructDeclaration sd = ts.sym; 951 if (sd.dtor) 952 return sd; 953 } 954 return null; 955 } 956 957 /******************************************* 958 * Set an array pointed to by eptr to evalue: 959 * eptr[0..edim] = evalue; 960 * Params: 961 * exp = the expression for which this operation is performed 962 * eptr = where to write the data to 963 * edim = number of times to write evalue to eptr[] 964 * tb = type of evalue 965 * evalue = value to write 966 * irs = context 967 * op = TOK.blit, TOK.assign, or TOK.construct 968 * Returns: 969 * created IR code 970 */ 971 private elem *setArray(Expression exp, elem *eptr, elem *edim, Type tb, elem *evalue, IRState *irs, int op) 972 { 973 assert(op == TOK.blit || op == TOK.assign || op == TOK.construct); 974 const sz = cast(uint)tb.size(); 975 976 Lagain: 977 int r; 978 switch (tb.ty) 979 { 980 case Tfloat80: 981 case Timaginary80: 982 r = RTLSYM_MEMSET80; 983 break; 984 case Tcomplex80: 985 r = RTLSYM_MEMSET160; 986 break; 987 case Tcomplex64: 988 r = RTLSYM_MEMSET128; 989 break; 990 case Tfloat32: 991 case Timaginary32: 992 if (!irs.params.is64bit) 993 goto default; // legacy binary compatibility 994 r = RTLSYM_MEMSETFLOAT; 995 break; 996 case Tfloat64: 997 case Timaginary64: 998 if (!irs.params.is64bit) 999 goto default; // legacy binary compatibility 1000 r = RTLSYM_MEMSETDOUBLE; 1001 break; 1002 1003 case Tstruct: 1004 { 1005 if (!irs.params.is64bit) 1006 goto default; 1007 1008 TypeStruct tc = cast(TypeStruct)tb; 1009 StructDeclaration sd = tc.sym; 1010 if (sd.arg1type && !sd.arg2type) 1011 { 1012 tb = sd.arg1type; 1013 goto Lagain; 1014 } 1015 goto default; 1016 } 1017 1018 case Tvector: 1019 r = RTLSYM_MEMSETSIMD; 1020 break; 1021 1022 default: 1023 switch (sz) 1024 { 1025 case 1: r = RTLSYM_MEMSET8; break; 1026 case 2: r = RTLSYM_MEMSET16; break; 1027 case 4: r = RTLSYM_MEMSET32; break; 1028 case 8: r = RTLSYM_MEMSET64; break; 1029 case 16: r = irs.params.is64bit ? RTLSYM_MEMSET128ii : RTLSYM_MEMSET128; break; 1030 default: r = RTLSYM_MEMSETN; break; 1031 } 1032 1033 /* Determine if we need to do postblit 1034 */ 1035 if (op != TOK.blit) 1036 { 1037 if (needsPostblit(tb) || needsDtor(tb)) 1038 { 1039 /* Need to do postblit/destructor. 1040 * void *_d_arraysetassign(void *p, void *value, int dim, TypeInfo ti); 1041 */ 1042 r = (op == TOK.construct) ? RTLSYM_ARRAYSETCTOR : RTLSYM_ARRAYSETASSIGN; 1043 evalue = el_una(OPaddr, TYnptr, evalue); 1044 // This is a hack so we can call postblits on const/immutable objects. 1045 elem *eti = getTypeInfo(exp.loc, tb.unSharedOf().mutableOf(), irs); 1046 elem *e = el_params(eti, edim, evalue, eptr, null); 1047 e = el_bin(OPcall,TYnptr,el_var(getRtlsym(r)),e); 1048 return e; 1049 } 1050 } 1051 1052 if (irs.params.is64bit && tybasic(evalue.Ety) == TYstruct && r != RTLSYM_MEMSETN) 1053 { 1054 /* If this struct is in-memory only, i.e. cannot necessarily be passed as 1055 * a gp register parameter. 1056 * The trouble is that memset() is expecting the argument to be in a gp 1057 * register, but the argument pusher may have other ideas on I64. 1058 * MEMSETN is inefficient, though. 1059 */ 1060 if (tybasic(evalue.ET.Tty) == TYstruct) 1061 { 1062 type *t1 = evalue.ET.Ttag.Sstruct.Sarg1type; 1063 type *t2 = evalue.ET.Ttag.Sstruct.Sarg2type; 1064 if (!t1 && !t2) 1065 { 1066 if (config.exe != EX_WIN64 || sz > 8) 1067 r = RTLSYM_MEMSETN; 1068 } 1069 else if (config.exe != EX_WIN64 && 1070 r == RTLSYM_MEMSET128ii && 1071 tyfloating(t1.Tty) && 1072 tyfloating(t2.Tty)) 1073 r = RTLSYM_MEMSET128; 1074 } 1075 } 1076 1077 if (r == RTLSYM_MEMSETN) 1078 { 1079 // void *_memsetn(void *p, void *value, int dim, int sizelem) 1080 evalue = addressElem(evalue, tb); 1081 elem *esz = el_long(TYsize_t, sz); 1082 elem *e = el_params(esz, edim, evalue, eptr, null); 1083 e = el_bin(OPcall,TYnptr,el_var(getRtlsym(r)),e); 1084 return e; 1085 } 1086 break; 1087 } 1088 if (sz > 1 && sz <= 8 && 1089 evalue.Eoper == OPconst && el_allbits(evalue, 0)) 1090 { 1091 r = RTLSYM_MEMSET8; 1092 edim = el_bin(OPmul, TYsize_t, edim, el_long(TYsize_t, sz)); 1093 } 1094 1095 if (config.exe == EX_WIN64 && sz > REGSIZE) 1096 { 1097 evalue = addressElem(evalue, tb); 1098 } 1099 // cast to the proper parameter type 1100 else if (r != RTLSYM_MEMSETN) 1101 { 1102 tym_t tym; 1103 switch (r) 1104 { 1105 case RTLSYM_MEMSET8: tym = TYchar; break; 1106 case RTLSYM_MEMSET16: tym = TYshort; break; 1107 case RTLSYM_MEMSET32: tym = TYlong; break; 1108 case RTLSYM_MEMSET64: tym = TYllong; break; 1109 case RTLSYM_MEMSET80: tym = TYldouble; break; 1110 case RTLSYM_MEMSET160: tym = TYcldouble; break; 1111 case RTLSYM_MEMSET128: tym = TYcdouble; break; 1112 case RTLSYM_MEMSET128ii: tym = TYucent; break; 1113 case RTLSYM_MEMSETFLOAT: tym = TYfloat; break; 1114 case RTLSYM_MEMSETDOUBLE: tym = TYdouble; break; 1115 case RTLSYM_MEMSETSIMD: tym = TYfloat4; break; 1116 default: 1117 assert(0); 1118 } 1119 tym = tym | (evalue.Ety & ~mTYbasic); 1120 evalue = addressElem(evalue, tb); 1121 evalue = el_una(OPind, tym, evalue); 1122 } 1123 1124 evalue = useOPstrpar(evalue); 1125 1126 // Be careful about parameter side effect ordering 1127 if (r == RTLSYM_MEMSET8) 1128 { 1129 elem *e = el_param(edim, evalue); 1130 return el_bin(OPmemset,TYnptr,eptr,e); 1131 } 1132 else 1133 { 1134 elem *e = el_params(edim, evalue, eptr, null); 1135 return el_bin(OPcall,TYnptr,el_var(getRtlsym(r)),e); 1136 } 1137 } 1138 1139 1140 __gshared StringTable!(Symbol*) *stringTab; 1141 1142 /******************************** 1143 * Reset stringTab[] between object files being emitted, because the symbols are local. 1144 */ 1145 void clearStringTab() 1146 { 1147 //printf("clearStringTab()\n"); 1148 if (stringTab) 1149 stringTab.reset(1000); // 1000 is arbitrary guess 1150 else 1151 { 1152 stringTab = new StringTable!(Symbol*)(); 1153 stringTab._init(1000); 1154 } 1155 } 1156 1157 1158 elem *toElem(Expression e, IRState *irs) 1159 { 1160 extern (C++) class ToElemVisitor : Visitor 1161 { 1162 IRState *irs; 1163 elem *result; 1164 1165 this(IRState *irs) 1166 { 1167 this.irs = irs; 1168 result = null; 1169 } 1170 1171 alias visit = Visitor.visit; 1172 1173 /*************************************** 1174 */ 1175 1176 override void visit(Expression e) 1177 { 1178 printf("[%s] %s: %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars()); 1179 assert(0); 1180 } 1181 1182 /************************************ 1183 */ 1184 override void visit(SymbolExp se) 1185 { 1186 elem *e; 1187 Type tb = (se.op == TOK.symbolOffset) ? se.var.type.toBasetype() : se.type.toBasetype(); 1188 int offset = (se.op == TOK.symbolOffset) ? cast(int)(cast(SymOffExp)se).offset : 0; 1189 VarDeclaration v = se.var.isVarDeclaration(); 1190 1191 //printf("[%s] SymbolExp.toElem('%s') %p, %s\n", se.loc.toChars(), se.toChars(), se, se.type.toChars()); 1192 //printf("\tparent = '%s'\n", se.var.parent ? se.var.parent.toChars() : "null"); 1193 if (se.op == TOK.variable && se.var.needThis()) 1194 { 1195 se.error("need `this` to access member `%s`", se.toChars()); 1196 result = el_long(TYsize_t, 0); 1197 return; 1198 } 1199 1200 /* The magic variable __ctfe is always false at runtime 1201 */ 1202 if (se.op == TOK.variable && v && v.ident == Id.ctfe) 1203 { 1204 result = el_long(totym(se.type), 0); 1205 return; 1206 } 1207 1208 if (FuncLiteralDeclaration fld = se.var.isFuncLiteralDeclaration()) 1209 { 1210 if (fld.tok == TOK.reserved) 1211 { 1212 // change to non-nested 1213 fld.tok = TOK.function_; 1214 fld.vthis = null; 1215 } 1216 if (!fld.deferToObj) 1217 { 1218 fld.deferToObj = true; 1219 irs.deferToObj.push(fld); 1220 } 1221 } 1222 1223 Symbol *s = toSymbol(se.var); 1224 FuncDeclaration fd = null; 1225 if (se.var.toParent2()) 1226 fd = se.var.toParent2().isFuncDeclaration(); 1227 1228 const bool nrvo = fd && fd.nrvo_can && fd.nrvo_var == se.var; 1229 if (nrvo) 1230 s = fd.shidden; 1231 1232 if (s.Sclass == SCauto || s.Sclass == SCparameter || s.Sclass == SCshadowreg) 1233 { 1234 if (fd && fd != irs.getFunc()) 1235 { 1236 // 'var' is a variable in an enclosing function. 1237 elem *ethis = getEthis(se.loc, irs, fd, null, se.originalScope); 1238 ethis = el_una(OPaddr, TYnptr, ethis); 1239 1240 /* https://issues.dlang.org/show_bug.cgi?id=9383 1241 * If 's' is a virtual function parameter 1242 * placed in closure, and actually accessed from in/out 1243 * contract, instead look at the original stack data. 1244 */ 1245 bool forceStackAccess = false; 1246 if (fd.isVirtual() && (fd.fdrequire || fd.fdensure)) 1247 { 1248 Dsymbol sx = irs.getFunc(); 1249 while (sx != fd) 1250 { 1251 if (sx.ident == Id.require || sx.ident == Id.ensure) 1252 { 1253 forceStackAccess = true; 1254 break; 1255 } 1256 sx = sx.toParent2(); 1257 } 1258 } 1259 1260 int soffset; 1261 if (v && v.offset && !forceStackAccess) 1262 soffset = v.offset; 1263 else 1264 { 1265 soffset = cast(int)s.Soffset; 1266 /* If fd is a non-static member function of a class or struct, 1267 * then ethis isn't the frame pointer. 1268 * ethis is the 'this' pointer to the class/struct instance. 1269 * We must offset it. 1270 */ 1271 if (fd.vthis) 1272 { 1273 Symbol *vs = toSymbol(fd.vthis); 1274 //printf("vs = %s, offset = %x, %p\n", vs.Sident, (int)vs.Soffset, vs); 1275 soffset -= vs.Soffset; 1276 } 1277 //printf("\tSoffset = x%x, sthis.Soffset = x%x\n", s.Soffset, irs.sthis.Soffset); 1278 } 1279 1280 if (!nrvo) 1281 soffset += offset; 1282 1283 e = el_bin(OPadd, TYnptr, ethis, el_long(TYnptr, soffset)); 1284 if (se.op == TOK.variable) 1285 e = el_una(OPind, TYnptr, e); 1286 if (ISREF(se.var) && !(ISX64REF(se.var) && v && v.offset && !forceStackAccess)) 1287 e = el_una(OPind, s.Stype.Tty, e); 1288 else if (se.op == TOK.symbolOffset && nrvo) 1289 { 1290 e = el_una(OPind, TYnptr, e); 1291 e = el_bin(OPadd, e.Ety, e, el_long(TYsize_t, offset)); 1292 } 1293 goto L1; 1294 } 1295 } 1296 1297 /* If var is a member of a closure 1298 */ 1299 if (v && v.offset) 1300 { 1301 assert(irs.sclosure); 1302 e = el_var(irs.sclosure); 1303 e = el_bin(OPadd, TYnptr, e, el_long(TYsize_t, v.offset)); 1304 if (se.op == TOK.variable) 1305 { 1306 e = el_una(OPind, totym(se.type), e); 1307 if (tybasic(e.Ety) == TYstruct) 1308 e.ET = Type_toCtype(se.type); 1309 elem_setLoc(e, se.loc); 1310 } 1311 if (ISREF(se.var) && !ISX64REF(se.var)) 1312 { 1313 e.Ety = TYnptr; 1314 e = el_una(OPind, s.Stype.Tty, e); 1315 } 1316 else if (se.op == TOK.symbolOffset && nrvo) 1317 { 1318 e = el_una(OPind, TYnptr, e); 1319 e = el_bin(OPadd, e.Ety, e, el_long(TYsize_t, offset)); 1320 } 1321 else if (se.op == TOK.symbolOffset) 1322 { 1323 e = el_bin(OPadd, e.Ety, e, el_long(TYsize_t, offset)); 1324 } 1325 goto L1; 1326 } 1327 1328 if (s.Sclass == SCauto && s.Ssymnum == -1) 1329 { 1330 //printf("\tadding symbol %s\n", s.Sident); 1331 symbol_add(s); 1332 } 1333 1334 if (se.var.isImportedSymbol()) 1335 { 1336 assert(se.op == TOK.variable); 1337 e = el_var(toImport(se.var)); 1338 e = el_una(OPind,s.Stype.Tty,e); 1339 } 1340 else if (ISREF(se.var)) 1341 { 1342 // Out parameters are really references 1343 e = el_var(s); 1344 e.Ety = TYnptr; 1345 if (se.op == TOK.variable) 1346 e = el_una(OPind, s.Stype.Tty, e); 1347 else if (offset) 1348 e = el_bin(OPadd, TYnptr, e, el_long(TYsize_t, offset)); 1349 } 1350 else if (se.op == TOK.variable) 1351 e = el_var(s); 1352 else 1353 { 1354 e = nrvo ? el_var(s) : el_ptr(s); 1355 e = el_bin(OPadd, e.Ety, e, el_long(TYsize_t, offset)); 1356 } 1357 L1: 1358 if (se.op == TOK.variable) 1359 { 1360 if (nrvo) 1361 { 1362 e.Ety = TYnptr; 1363 e = el_una(OPind, 0, e); 1364 } 1365 1366 tym_t tym; 1367 if (se.var.storage_class & STC.lazy_) 1368 tym = TYdelegate; // Tdelegate as C type 1369 else if (tb.ty == Tfunction) 1370 tym = s.Stype.Tty; 1371 else 1372 tym = totym(se.type); 1373 1374 e.Ejty = cast(ubyte)(e.Ety = tym); 1375 1376 if (tybasic(tym) == TYstruct) 1377 { 1378 e.ET = Type_toCtype(se.type); 1379 } 1380 else if (tybasic(tym) == TYarray) 1381 { 1382 e.Ejty = e.Ety = TYstruct; 1383 e.ET = Type_toCtype(se.type); 1384 } 1385 else if (tysimd(tym)) 1386 { 1387 e.ET = Type_toCtype(se.type); 1388 } 1389 } 1390 elem_setLoc(e,se.loc); 1391 result = e; 1392 } 1393 1394 /************************************** 1395 */ 1396 1397 override void visit(FuncExp fe) 1398 { 1399 //printf("FuncExp.toElem() %s\n", fe.toChars()); 1400 FuncLiteralDeclaration fld = fe.fd; 1401 1402 if (fld.tok == TOK.reserved && fe.type.ty == Tpointer) 1403 { 1404 // change to non-nested 1405 fld.tok = TOK.function_; 1406 fld.vthis = null; 1407 } 1408 if (!fld.deferToObj) 1409 { 1410 fld.deferToObj = true; 1411 irs.deferToObj.push(fld); 1412 } 1413 1414 Symbol *s = toSymbol(fld); 1415 elem *e = el_ptr(s); 1416 if (fld.isNested()) 1417 { 1418 elem *ethis; 1419 // Delegate literals report isNested() even if they are in global scope, 1420 // so we need to check that the parent is a function. 1421 if (!fld.toParent2().isFuncDeclaration()) 1422 ethis = el_long(TYnptr, 0); 1423 else 1424 ethis = getEthis(fe.loc, irs, fld); 1425 e = el_pair(TYdelegate, ethis, e); 1426 } 1427 elem_setLoc(e, fe.loc); 1428 result = e; 1429 } 1430 1431 override void visit(DeclarationExp de) 1432 { 1433 //printf("DeclarationExp.toElem() %s\n", de.toChars()); 1434 result = Dsymbol_toElem(de.declaration); 1435 } 1436 1437 /*************************************** 1438 */ 1439 1440 override void visit(TypeidExp e) 1441 { 1442 //printf("TypeidExp.toElem() %s\n", e.toChars()); 1443 if (Type t = isType(e.obj)) 1444 { 1445 result = getTypeInfo(e.loc, t, irs); 1446 result = el_bin(OPadd, result.Ety, result, el_long(TYsize_t, t.vtinfo.offset)); 1447 return; 1448 } 1449 if (Expression ex = isExpression(e.obj)) 1450 { 1451 auto tc = ex.type.toBasetype().isTypeClass(); 1452 assert(tc); 1453 // generate **classptr to get the classinfo 1454 result = toElem(ex, irs); 1455 result = el_una(OPind,TYnptr,result); 1456 result = el_una(OPind,TYnptr,result); 1457 // Add extra indirection for interfaces 1458 if (tc.sym.isInterfaceDeclaration()) 1459 result = el_una(OPind,TYnptr,result); 1460 return; 1461 } 1462 assert(0); 1463 } 1464 1465 /*************************************** 1466 */ 1467 1468 override void visit(ThisExp te) 1469 { 1470 //printf("ThisExp.toElem()\n"); 1471 assert(irs.sthis); 1472 1473 elem *ethis; 1474 if (te.var) 1475 { 1476 assert(te.var.parent); 1477 FuncDeclaration fd = te.var.toParent2().isFuncDeclaration(); 1478 assert(fd); 1479 ethis = getEthis(te.loc, irs, fd); 1480 ethis = fixEthis2(ethis, fd); 1481 } 1482 else 1483 { 1484 ethis = el_var(irs.sthis); 1485 ethis = fixEthis2(ethis, irs.getFunc()); 1486 } 1487 1488 if (te.type.ty == Tstruct) 1489 { 1490 ethis = el_una(OPind, TYstruct, ethis); 1491 ethis.ET = Type_toCtype(te.type); 1492 } 1493 elem_setLoc(ethis,te.loc); 1494 result = ethis; 1495 } 1496 1497 /*************************************** 1498 */ 1499 1500 override void visit(IntegerExp ie) 1501 { 1502 elem *e = el_long(totym(ie.type), ie.getInteger()); 1503 elem_setLoc(e,ie.loc); 1504 result = e; 1505 } 1506 1507 /*************************************** 1508 */ 1509 1510 override void visit(RealExp re) 1511 { 1512 //printf("RealExp.toElem(%p) %s\n", re, re.toChars()); 1513 elem *e = el_long(TYint, 0); 1514 tym_t ty = totym(re.type.toBasetype()); 1515 switch (tybasic(ty)) 1516 { 1517 case TYfloat: 1518 case TYifloat: 1519 e.EV.Vfloat = cast(float) re.value; 1520 break; 1521 1522 case TYdouble: 1523 case TYidouble: 1524 e.EV.Vdouble = cast(double) re.value; 1525 break; 1526 1527 case TYldouble: 1528 case TYildouble: 1529 e.EV.Vldouble = re.value; 1530 break; 1531 1532 default: 1533 printf("ty = %d, tym = %x, re=%s, re.type=%s, re.type.toBasetype=%s\n", 1534 re.type.ty, ty, re.toChars(), re.type.toChars(), re.type.toBasetype().toChars()); 1535 assert(0); 1536 } 1537 e.Ety = ty; 1538 result = e; 1539 } 1540 1541 /*************************************** 1542 */ 1543 1544 override void visit(ComplexExp ce) 1545 { 1546 1547 //printf("ComplexExp.toElem(%p) %s\n", ce, ce.toChars()); 1548 1549 elem *e = el_long(TYint, 0); 1550 real_t re = ce.value.re; 1551 real_t im = ce.value.im; 1552 1553 tym_t ty = totym(ce.type); 1554 switch (tybasic(ty)) 1555 { 1556 case TYcfloat: 1557 union UF { float f; uint i; } 1558 e.EV.Vcfloat.re = cast(float) re; 1559 if (CTFloat.isSNaN(re)) 1560 { 1561 UF u; 1562 u.f = e.EV.Vcfloat.re; 1563 u.i &= 0xFFBFFFFFL; 1564 e.EV.Vcfloat.re = u.f; 1565 } 1566 e.EV.Vcfloat.im = cast(float) im; 1567 if (CTFloat.isSNaN(im)) 1568 { 1569 UF u; 1570 u.f = e.EV.Vcfloat.im; 1571 u.i &= 0xFFBFFFFFL; 1572 e.EV.Vcfloat.im = u.f; 1573 } 1574 break; 1575 1576 case TYcdouble: 1577 union UD { double d; ulong i; } 1578 e.EV.Vcdouble.re = cast(double) re; 1579 if (CTFloat.isSNaN(re)) 1580 { 1581 UD u; 1582 u.d = e.EV.Vcdouble.re; 1583 u.i &= 0xFFF7FFFFFFFFFFFFUL; 1584 e.EV.Vcdouble.re = u.d; 1585 } 1586 e.EV.Vcdouble.im = cast(double) im; 1587 if (CTFloat.isSNaN(re)) 1588 { 1589 UD u; 1590 u.d = e.EV.Vcdouble.im; 1591 u.i &= 0xFFF7FFFFFFFFFFFFUL; 1592 e.EV.Vcdouble.im = u.d; 1593 } 1594 break; 1595 1596 case TYcldouble: 1597 e.EV.Vcldouble.re = re; 1598 e.EV.Vcldouble.im = im; 1599 break; 1600 1601 default: 1602 assert(0); 1603 } 1604 e.Ety = ty; 1605 result = e; 1606 } 1607 1608 /*************************************** 1609 */ 1610 1611 override void visit(NullExp ne) 1612 { 1613 result = el_long(totym(ne.type), 0); 1614 } 1615 1616 /*************************************** 1617 */ 1618 1619 override void visit(StringExp se) 1620 { 1621 //printf("StringExp.toElem() %s, type = %s\n", se.toChars(), se.type.toChars()); 1622 1623 elem *e; 1624 Type tb = se.type.toBasetype(); 1625 if (tb.ty == Tarray) 1626 { 1627 Symbol *si = toStringSymbol(se); 1628 e = el_pair(TYdarray, el_long(TYsize_t, se.numberOfCodeUnits()), el_ptr(si)); 1629 } 1630 else if (tb.ty == Tsarray) 1631 { 1632 Symbol *si = toStringSymbol(se); 1633 e = el_var(si); 1634 e.Ejty = e.Ety = TYstruct; 1635 e.ET = si.Stype; 1636 e.ET.Tcount++; 1637 } 1638 else if (tb.ty == Tpointer) 1639 { 1640 e = el_calloc(); 1641 e.Eoper = OPstring; 1642 // freed in el_free 1643 uint len = cast(uint)((se.numberOfCodeUnits() + 1) * se.sz); 1644 e.EV.Vstring = cast(char *)mem_malloc2(cast(uint)len); 1645 se.writeTo(e.EV.Vstring, true); 1646 e.EV.Vstrlen = len; 1647 e.Ety = TYnptr; 1648 } 1649 else 1650 { 1651 printf("type is %s\n", se.type.toChars()); 1652 assert(0); 1653 } 1654 elem_setLoc(e,se.loc); 1655 result = e; 1656 } 1657 1658 override void visit(NewExp ne) 1659 { 1660 //printf("NewExp.toElem() %s\n", ne.toChars()); 1661 Type t = ne.type.toBasetype(); 1662 //printf("\ttype = %s\n", t.toChars()); 1663 //if (ne.member) 1664 //printf("\tmember = %s\n", ne.member.toChars()); 1665 elem *e; 1666 Type ectype; 1667 if (t.ty == Tclass) 1668 { 1669 auto tclass = ne.newtype.toBasetype().isTypeClass(); 1670 assert(tclass); 1671 ClassDeclaration cd = tclass.sym; 1672 1673 /* Things to do: 1674 * 1) ex: call allocator 1675 * 2) ey: set vthis for nested classes 1676 * 2) ew: set vthis2 for nested classes 1677 * 3) ez: call constructor 1678 */ 1679 1680 elem *ex = null; 1681 elem *ey = null; 1682 elem *ew = null; 1683 elem *ezprefix = null; 1684 elem *ez = null; 1685 1686 if (ne.allocator || ne.onstack) 1687 { 1688 if (ne.onstack) 1689 { 1690 /* Create an instance of the class on the stack, 1691 * and call it stmp. 1692 * Set ex to be the &stmp. 1693 */ 1694 .type *tc = type_struct_class(tclass.sym.toChars(), 1695 tclass.sym.alignsize, tclass.sym.structsize, 1696 null, null, 1697 false, false, true, false); 1698 tc.Tcount--; 1699 Symbol *stmp = symbol_genauto(tc); 1700 ex = el_ptr(stmp); 1701 } 1702 else 1703 { 1704 ex = el_var(toSymbol(ne.allocator)); 1705 ex = callfunc(ne.loc, irs, 1, ne.type, ex, ne.allocator.type, 1706 ne.allocator, ne.allocator.type, null, ne.newargs); 1707 } 1708 1709 Symbol *si = toInitializer(tclass.sym); 1710 elem *ei = el_var(si); 1711 1712 if (cd.isNested()) 1713 { 1714 ey = el_same(&ex); 1715 ez = el_copytree(ey); 1716 if (cd.vthis2) 1717 ew = el_copytree(ey); 1718 } 1719 else if (ne.member) 1720 ez = el_same(&ex); 1721 1722 ex = el_una(OPind, TYstruct, ex); 1723 ex = elAssign(ex, ei, null, Type_toCtype(tclass).Tnext); 1724 ex = el_una(OPaddr, TYnptr, ex); 1725 ectype = tclass; 1726 } 1727 else 1728 { 1729 Symbol *csym = toSymbol(cd); 1730 const rtl = global.params.ehnogc && ne.thrownew ? RTLSYM_NEWTHROW : RTLSYM_NEWCLASS; 1731 ex = el_bin(OPcall,TYnptr,el_var(getRtlsym(rtl)),el_ptr(csym)); 1732 toTraceGC(irs, ex, ne.loc); 1733 ectype = null; 1734 1735 if (cd.isNested()) 1736 { 1737 ey = el_same(&ex); 1738 ez = el_copytree(ey); 1739 if (cd.vthis2) 1740 ew = el_copytree(ey); 1741 } 1742 else if (ne.member) 1743 ez = el_same(&ex); 1744 //elem_print(ex); 1745 //elem_print(ey); 1746 //elem_print(ez); 1747 } 1748 1749 if (ne.thisexp) 1750 { 1751 ClassDeclaration cdthis = ne.thisexp.type.isClassHandle(); 1752 assert(cdthis); 1753 //printf("cd = %s\n", cd.toChars()); 1754 //printf("cdthis = %s\n", cdthis.toChars()); 1755 assert(cd.isNested()); 1756 int offset = 0; 1757 Dsymbol cdp = cd.toParentLocal(); // class we're nested in 1758 1759 //printf("member = %p\n", member); 1760 //printf("cdp = %s\n", cdp.toChars()); 1761 //printf("cdthis = %s\n", cdthis.toChars()); 1762 if (cdp != cdthis) 1763 { 1764 int i = cdp.isClassDeclaration().isBaseOf(cdthis, &offset); 1765 assert(i); 1766 } 1767 elem *ethis = toElem(ne.thisexp, irs); 1768 if (offset) 1769 ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYsize_t, offset)); 1770 1771 if (!cd.vthis) 1772 { 1773 ne.error("forward reference to `%s`", cd.toChars()); 1774 } 1775 else 1776 { 1777 ey = el_bin(OPadd, TYnptr, ey, el_long(TYsize_t, cd.vthis.offset)); 1778 ey = el_una(OPind, TYnptr, ey); 1779 ey = el_bin(OPeq, TYnptr, ey, ethis); 1780 } 1781 //printf("ex: "); elem_print(ex); 1782 //printf("ey: "); elem_print(ey); 1783 //printf("ez: "); elem_print(ez); 1784 } 1785 else if (cd.isNested()) 1786 { 1787 /* Initialize cd.vthis: 1788 * *(ey + cd.vthis.offset) = this; 1789 */ 1790 ey = setEthis(ne.loc, irs, ey, cd); 1791 } 1792 1793 if (cd.vthis2) 1794 { 1795 /* Initialize cd.vthis2: 1796 * *(ew + cd.vthis2.offset) = this; 1797 */ 1798 assert(ew); 1799 ew = setEthis(ne.loc, irs, ew, cd, true); 1800 } 1801 1802 if (ne.member) 1803 { 1804 if (ne.argprefix) 1805 ezprefix = toElem(ne.argprefix, irs); 1806 // Call constructor 1807 ez = callfunc(ne.loc, irs, 1, ne.type, ez, ectype, ne.member, ne.member.type, null, ne.arguments); 1808 } 1809 1810 e = el_combine(ex, ey); 1811 e = el_combine(e, ew); 1812 e = el_combine(e, ezprefix); 1813 e = el_combine(e, ez); 1814 } 1815 else if (t.ty == Tpointer && t.nextOf().toBasetype().ty == Tstruct) 1816 { 1817 t = ne.newtype.toBasetype(); 1818 TypeStruct tclass = t.isTypeStruct(); 1819 StructDeclaration sd = tclass.sym; 1820 1821 /* Things to do: 1822 * 1) ex: call allocator 1823 * 2) ey: set vthis for nested structs 1824 * 2) ew: set vthis2 for nested structs 1825 * 3) ez: call constructor 1826 */ 1827 1828 elem *ex = null; 1829 elem *ey = null; 1830 elem *ew = null; 1831 elem *ezprefix = null; 1832 elem *ez = null; 1833 1834 if (ne.allocator) 1835 { 1836 1837 ex = el_var(toSymbol(ne.allocator)); 1838 ex = callfunc(ne.loc, irs, 1, ne.type, ex, ne.allocator.type, 1839 ne.allocator, ne.allocator.type, null, ne.newargs); 1840 1841 ectype = tclass; 1842 } 1843 else 1844 { 1845 // call _d_newitemT(ti) 1846 e = getTypeInfo(ne.loc, ne.newtype, irs); 1847 1848 int rtl = t.isZeroInit(Loc.initial) ? RTLSYM_NEWITEMT : RTLSYM_NEWITEMIT; 1849 ex = el_bin(OPcall,TYnptr,el_var(getRtlsym(rtl)),e); 1850 toTraceGC(irs, ex, ne.loc); 1851 1852 ectype = null; 1853 } 1854 1855 elem *ev = el_same(&ex); 1856 1857 if (ne.argprefix) 1858 ezprefix = toElem(ne.argprefix, irs); 1859 if (ne.member) 1860 { 1861 if (sd.isNested()) 1862 { 1863 ey = el_copytree(ev); 1864 1865 /* Initialize sd.vthis: 1866 * *(ey + sd.vthis.offset) = this; 1867 */ 1868 ey = setEthis(ne.loc, irs, ey, sd); 1869 if (sd.vthis2) 1870 { 1871 /* Initialize sd.vthis2: 1872 * *(ew + sd.vthis2.offset) = this1; 1873 */ 1874 ew = el_copytree(ev); 1875 ew = setEthis(ne.loc, irs, ew, sd, true); 1876 } 1877 } 1878 1879 // Call constructor 1880 ez = callfunc(ne.loc, irs, 1, ne.type, ev, ectype, ne.member, ne.member.type, null, ne.arguments); 1881 /* Structs return a ref, which gets automatically dereferenced. 1882 * But we want a pointer to the instance. 1883 */ 1884 ez = el_una(OPaddr, TYnptr, ez); 1885 } 1886 else 1887 { 1888 StructLiteralExp sle = StructLiteralExp.create(ne.loc, sd, ne.arguments, t); 1889 ez = toElemStructLit(sle, irs, TOK.construct, ev.EV.Vsym, false); 1890 } 1891 //elem_print(ex); 1892 //elem_print(ey); 1893 //elem_print(ez); 1894 1895 e = el_combine(ex, ey); 1896 e = el_combine(e, ew); 1897 e = el_combine(e, ezprefix); 1898 e = el_combine(e, ez); 1899 } 1900 else if (auto tda = t.isTypeDArray()) 1901 { 1902 elem *ezprefix = ne.argprefix ? toElem(ne.argprefix, irs) : null; 1903 1904 assert(ne.arguments && ne.arguments.dim >= 1); 1905 if (ne.arguments.dim == 1) 1906 { 1907 // Single dimension array allocations 1908 Expression arg = (*ne.arguments)[0]; // gives array length 1909 e = toElem(arg, irs); 1910 1911 // call _d_newT(ti, arg) 1912 e = el_param(e, getTypeInfo(ne.loc, ne.type, irs)); 1913 int rtl = tda.next.isZeroInit(Loc.initial) ? RTLSYM_NEWARRAYT : RTLSYM_NEWARRAYIT; 1914 e = el_bin(OPcall,TYdarray,el_var(getRtlsym(rtl)),e); 1915 toTraceGC(irs, e, ne.loc); 1916 } 1917 else 1918 { 1919 // Multidimensional array allocations 1920 foreach (i; 0 .. ne.arguments.dim) 1921 { 1922 assert(t.ty == Tarray); 1923 t = t.nextOf(); 1924 assert(t); 1925 } 1926 1927 // Allocate array of dimensions on the stack 1928 Symbol *sdata = null; 1929 elem *earray = ExpressionsToStaticArray(ne.loc, ne.arguments, &sdata); 1930 1931 e = el_pair(TYdarray, el_long(TYsize_t, ne.arguments.dim), el_ptr(sdata)); 1932 if (config.exe == EX_WIN64) 1933 e = addressElem(e, Type.tsize_t.arrayOf()); 1934 e = el_param(e, getTypeInfo(ne.loc, ne.type, irs)); 1935 int rtl = t.isZeroInit(Loc.initial) ? RTLSYM_NEWARRAYMTX : RTLSYM_NEWARRAYMITX; 1936 e = el_bin(OPcall,TYdarray,el_var(getRtlsym(rtl)),e); 1937 toTraceGC(irs, e, ne.loc); 1938 1939 e = el_combine(earray, e); 1940 } 1941 e = el_combine(ezprefix, e); 1942 } 1943 else if (auto tp = t.isTypePointer()) 1944 { 1945 elem *ezprefix = ne.argprefix ? toElem(ne.argprefix, irs) : null; 1946 1947 // call _d_newitemT(ti) 1948 e = getTypeInfo(ne.loc, ne.newtype, irs); 1949 1950 int rtl = tp.next.isZeroInit(Loc.initial) ? RTLSYM_NEWITEMT : RTLSYM_NEWITEMIT; 1951 e = el_bin(OPcall,TYnptr,el_var(getRtlsym(rtl)),e); 1952 toTraceGC(irs, e, ne.loc); 1953 1954 if (ne.arguments && ne.arguments.dim == 1) 1955 { 1956 /* ezprefix, ts=_d_newitemT(ti), *ts=arguments[0], ts 1957 */ 1958 elem *e2 = toElem((*ne.arguments)[0], irs); 1959 1960 Symbol *ts = symbol_genauto(Type_toCtype(tp)); 1961 elem *eeq1 = el_bin(OPeq, TYnptr, el_var(ts), e); 1962 1963 elem *ederef = el_una(OPind, e2.Ety, el_var(ts)); 1964 elem *eeq2 = el_bin(OPeq, e2.Ety, ederef, e2); 1965 1966 e = el_combine(eeq1, eeq2); 1967 e = el_combine(e, el_var(ts)); 1968 //elem_print(e); 1969 } 1970 e = el_combine(ezprefix, e); 1971 } 1972 else 1973 { 1974 ne.error("Internal Compiler Error: cannot new type `%s`\n", t.toChars()); 1975 assert(0); 1976 } 1977 1978 elem_setLoc(e,ne.loc); 1979 result = e; 1980 } 1981 1982 //////////////////////////// Unary /////////////////////////////// 1983 1984 /*************************************** 1985 */ 1986 1987 override void visit(NegExp ne) 1988 { 1989 elem *e = toElem(ne.e1, irs); 1990 Type tb1 = ne.e1.type.toBasetype(); 1991 1992 assert(tb1.ty != Tarray && tb1.ty != Tsarray); 1993 1994 switch (tb1.ty) 1995 { 1996 case Tvector: 1997 { 1998 // rewrite (-e) as (0-e) 1999 elem *ez = el_calloc(); 2000 ez.Eoper = OPconst; 2001 ez.Ety = e.Ety; 2002 ez.EV.Vcent.lsw = 0; 2003 ez.EV.Vcent.msw = 0; 2004 e = el_bin(OPmin, totym(ne.type), ez, e); 2005 break; 2006 } 2007 2008 default: 2009 e = el_una(OPneg, totym(ne.type), e); 2010 break; 2011 } 2012 2013 elem_setLoc(e,ne.loc); 2014 result = e; 2015 } 2016 2017 /*************************************** 2018 */ 2019 2020 override void visit(ComExp ce) 2021 { 2022 elem *e1 = toElem(ce.e1, irs); 2023 Type tb1 = ce.e1.type.toBasetype(); 2024 tym_t ty = totym(ce.type); 2025 2026 assert(tb1.ty != Tarray && tb1.ty != Tsarray); 2027 2028 elem *e; 2029 switch (tb1.ty) 2030 { 2031 case Tbool: 2032 e = el_bin(OPxor, ty, e1, el_long(ty, 1)); 2033 break; 2034 2035 case Tvector: 2036 { 2037 // rewrite (~e) as (e^~0) 2038 elem *ec = el_calloc(); 2039 ec.Eoper = OPconst; 2040 ec.Ety = e1.Ety; 2041 ec.EV.Vcent.lsw = ~0L; 2042 ec.EV.Vcent.msw = ~0L; 2043 e = el_bin(OPxor, ty, e1, ec); 2044 break; 2045 } 2046 2047 default: 2048 e = el_una(OPcom,ty,e1); 2049 break; 2050 } 2051 2052 elem_setLoc(e,ce.loc); 2053 result = e; 2054 } 2055 2056 /*************************************** 2057 */ 2058 2059 override void visit(NotExp ne) 2060 { 2061 elem *e = el_una(OPnot, totym(ne.type), toElem(ne.e1, irs)); 2062 elem_setLoc(e,ne.loc); 2063 result = e; 2064 } 2065 2066 2067 /*************************************** 2068 */ 2069 2070 override void visit(HaltExp he) 2071 { 2072 result = genHalt(he.loc); 2073 } 2074 2075 /******************************************** 2076 */ 2077 2078 override void visit(AssertExp ae) 2079 { 2080 // https://dlang.org/spec/expression.html#assert_expressions 2081 //printf("AssertExp.toElem() %s\n", toChars()); 2082 elem *e; 2083 if (irs.params.useAssert == CHECKENABLE.on) 2084 { 2085 if (irs.params.checkAction == CHECKACTION.C) 2086 { 2087 auto econd = toElem(ae.e1, irs); 2088 auto ea = callCAssert(irs, ae.e1.loc, ae.e1, ae.msg, null); 2089 auto eo = el_bin(OPoror, TYvoid, econd, ea); 2090 elem_setLoc(eo, ae.loc); 2091 result = eo; 2092 return; 2093 } 2094 2095 if (irs.params.checkAction == CHECKACTION.halt) 2096 { 2097 /* Generate: 2098 * ae.e1 || halt 2099 */ 2100 auto econd = toElem(ae.e1, irs); 2101 auto ea = genHalt(ae.loc); 2102 auto eo = el_bin(OPoror, TYvoid, econd, ea); 2103 elem_setLoc(eo, ae.loc); 2104 result = eo; 2105 return; 2106 } 2107 2108 e = toElem(ae.e1, irs); 2109 Symbol *ts = null; 2110 elem *einv = null; 2111 Type t1 = ae.e1.type.toBasetype(); 2112 2113 FuncDeclaration inv; 2114 2115 // If e1 is a class object, call the class invariant on it 2116 if (irs.params.useInvariants == CHECKENABLE.on && t1.ty == Tclass && 2117 !(cast(TypeClass)t1).sym.isInterfaceDeclaration() && 2118 !(cast(TypeClass)t1).sym.isCPPclass()) 2119 { 2120 ts = symbol_genauto(Type_toCtype(t1)); 2121 einv = el_bin(OPcall, TYvoid, el_var(getRtlsym(RTLSYM_DINVARIANT)), el_var(ts)); 2122 } 2123 else if (irs.params.useInvariants == CHECKENABLE.on && 2124 t1.ty == Tpointer && 2125 t1.nextOf().ty == Tstruct && 2126 (inv = (cast(TypeStruct)t1.nextOf()).sym.inv) !is null) 2127 { 2128 // If e1 is a struct object, call the struct invariant on it 2129 ts = symbol_genauto(Type_toCtype(t1)); 2130 einv = callfunc(ae.loc, irs, 1, inv.type.nextOf(), el_var(ts), ae.e1.type, inv, inv.type, null, null); 2131 } 2132 2133 // Construct: (e1 || ModuleAssert(line)) 2134 Module m = cast(Module)irs.blx._module; 2135 char *mname = cast(char*)m.srcfile.toChars(); 2136 2137 //printf("filename = '%s'\n", ae.loc.filename); 2138 //printf("module = '%s'\n", m.srcfile.toChars()); 2139 2140 /* Determine if we are in a unittest 2141 */ 2142 FuncDeclaration fd = irs.getFunc(); 2143 UnitTestDeclaration ud = fd ? fd.isUnitTestDeclaration() : null; 2144 2145 /* If the source file name has changed, probably due 2146 * to a #line directive. 2147 */ 2148 elem *ea; 2149 if (ae.loc.filename && (ae.msg || strcmp(ae.loc.filename, mname) != 0)) 2150 { 2151 const(char)* id = ae.loc.filename; 2152 size_t len = strlen(id); 2153 Symbol *si = toStringSymbol(id, len, 1); 2154 elem *efilename = el_pair(TYdarray, el_long(TYsize_t, len), el_ptr(si)); 2155 if (config.exe == EX_WIN64) 2156 efilename = addressElem(efilename, Type.tstring, true); 2157 2158 if (ae.msg) 2159 { 2160 /* https://issues.dlang.org/show_bug.cgi?id=8360 2161 * If the condition is evalated to true, 2162 * msg is not evaluated at all. so should use 2163 * toElemDtor(msg, irs) instead of toElem(msg, irs). 2164 */ 2165 elem *emsg = toElemDtor(ae.msg, irs); 2166 emsg = array_toDarray(ae.msg.type, emsg); 2167 if (config.exe == EX_WIN64) 2168 emsg = addressElem(emsg, Type.tvoid.arrayOf(), false); 2169 2170 ea = el_var(getRtlsym(ud ? RTLSYM_DUNITTEST_MSG : RTLSYM_DASSERT_MSG)); 2171 ea = el_bin(OPcall, TYvoid, ea, el_params(el_long(TYint, ae.loc.linnum), efilename, emsg, null)); 2172 } 2173 else 2174 { 2175 ea = el_var(getRtlsym(ud ? RTLSYM_DUNITTEST : RTLSYM_DASSERT)); 2176 ea = el_bin(OPcall, TYvoid, ea, el_param(el_long(TYint, ae.loc.linnum), efilename)); 2177 } 2178 } 2179 else 2180 { 2181 auto eassert = el_var(getRtlsym(ud ? RTLSYM_DUNITTESTP : RTLSYM_DASSERTP)); 2182 auto efile = toEfilenamePtr(m); 2183 auto eline = el_long(TYint, ae.loc.linnum); 2184 ea = el_bin(OPcall, TYvoid, eassert, el_param(eline, efile)); 2185 } 2186 if (einv) 2187 { 2188 // tmp = e, e || assert, e.inv 2189 elem *eassign = el_bin(OPeq, e.Ety, el_var(ts), e); 2190 e = el_combine(eassign, el_bin(OPoror, TYvoid, el_var(ts), ea)); 2191 e = el_combine(e, einv); 2192 } 2193 else 2194 e = el_bin(OPoror,TYvoid,e,ea); 2195 } 2196 else 2197 { 2198 // BUG: should replace assert(0); with a HLT instruction 2199 e = el_long(TYint, 0); 2200 } 2201 elem_setLoc(e,ae.loc); 2202 result = e; 2203 } 2204 2205 override void visit(PostExp pe) 2206 { 2207 //printf("PostExp.toElem() '%s'\n", pe.toChars()); 2208 elem *e = toElem(pe.e1, irs); 2209 elem *einc = toElem(pe.e2, irs); 2210 e = el_bin((pe.op == TOK.plusPlus) ? OPpostinc : OPpostdec, 2211 e.Ety,e,einc); 2212 elem_setLoc(e,pe.loc); 2213 result = e; 2214 } 2215 2216 //////////////////////////// Binary /////////////////////////////// 2217 2218 /******************************************** 2219 */ 2220 elem *toElemBin(BinExp be, int op) 2221 { 2222 //printf("toElemBin() '%s'\n", be.toChars()); 2223 2224 Type tb1 = be.e1.type.toBasetype(); 2225 Type tb2 = be.e2.type.toBasetype(); 2226 2227 assert(!((tb1.ty == Tarray || tb1.ty == Tsarray || 2228 tb2.ty == Tarray || tb2.ty == Tsarray) && 2229 tb2.ty != Tvoid && 2230 op != OPeq && op != OPandand && op != OPoror)); 2231 2232 tym_t tym = totym(be.type); 2233 2234 elem *el = toElem(be.e1, irs); 2235 elem *er = toElem(be.e2, irs); 2236 elem *e = el_bin(op,tym,el,er); 2237 2238 elem_setLoc(e,be.loc); 2239 return e; 2240 } 2241 2242 elem *toElemBinAssign(BinAssignExp be, int op) 2243 { 2244 //printf("toElemBinAssign() '%s'\n", be.toChars()); 2245 2246 Type tb1 = be.e1.type.toBasetype(); 2247 Type tb2 = be.e2.type.toBasetype(); 2248 2249 assert(!((tb1.ty == Tarray || tb1.ty == Tsarray || 2250 tb2.ty == Tarray || tb2.ty == Tsarray) && 2251 tb2.ty != Tvoid && 2252 op != OPeq && op != OPandand && op != OPoror)); 2253 2254 tym_t tym = totym(be.type); 2255 2256 elem *el; 2257 elem *ev; 2258 if (be.e1.op == TOK.cast_) 2259 { 2260 int depth = 0; 2261 Expression e1 = be.e1; 2262 while (e1.op == TOK.cast_) 2263 { 2264 ++depth; 2265 e1 = (cast(CastExp)e1).e1; 2266 } 2267 assert(depth > 0); 2268 2269 el = toElem(e1, irs); 2270 el = addressElem(el, e1.type.pointerTo()); 2271 ev = el_same(&el); 2272 2273 el = el_una(OPind, totym(e1.type), el); 2274 2275 ev = el_una(OPind, tym, ev); 2276 2277 foreach (d; 0 .. depth) 2278 { 2279 e1 = be.e1; 2280 foreach (i; 1 .. depth - d) 2281 e1 = (cast(CastExp)e1).e1; 2282 2283 el = toElemCast(cast(CastExp)e1, el, true); 2284 } 2285 } 2286 else 2287 { 2288 el = toElem(be.e1, irs); 2289 el = addressElem(el, be.e1.type.pointerTo()); 2290 ev = el_same(&el); 2291 2292 el = el_una(OPind, tym, el); 2293 ev = el_una(OPind, tym, ev); 2294 } 2295 elem *er = toElem(be.e2, irs); 2296 elem *e = el_bin(op, tym, el, er); 2297 e = el_combine(e, ev); 2298 2299 elem_setLoc(e,be.loc); 2300 return e; 2301 } 2302 2303 /*************************************** 2304 */ 2305 2306 override void visit(AddExp e) 2307 { 2308 result = toElemBin(e, OPadd); 2309 } 2310 2311 /*************************************** 2312 */ 2313 2314 override void visit(MinExp e) 2315 { 2316 result = toElemBin(e, OPmin); 2317 } 2318 2319 /***************************************** 2320 * Evaluate elem and convert to dynamic array suitable for a function argument. 2321 */ 2322 elem *eval_Darray(Expression e) 2323 { 2324 elem *ex = toElem(e, irs); 2325 ex = array_toDarray(e.type, ex); 2326 if (config.exe == EX_WIN64) 2327 { 2328 ex = addressElem(ex, Type.tvoid.arrayOf(), false); 2329 } 2330 return ex; 2331 } 2332 2333 /*************************************** 2334 * http://dlang.org/spec/expression.html#cat_expressions 2335 */ 2336 2337 override void visit(CatExp ce) 2338 { 2339 /* Do this check during code gen rather than semantic() because concatenation is 2340 * allowed in CTFE, and cannot distinguish that in semantic(). 2341 */ 2342 if (irs.params.betterC) 2343 { 2344 error(ce.loc, "array concatenation of expression `%s` requires the GC which is not available with -betterC", ce.toChars()); 2345 result = el_long(TYint, 0); 2346 return; 2347 } 2348 2349 Type tb1 = ce.e1.type.toBasetype(); 2350 Type tb2 = ce.e2.type.toBasetype(); 2351 2352 Type ta = (tb1.ty == Tarray || tb1.ty == Tsarray) ? tb1 : tb2; 2353 2354 elem *e; 2355 if (ce.e1.op == TOK.concatenate) 2356 { 2357 CatExp ex = ce; 2358 2359 // Flatten ((a ~ b) ~ c) to [a, b, c] 2360 Elems elems; 2361 elems.shift(array_toDarray(ex.e2.type, toElem(ex.e2, irs))); 2362 do 2363 { 2364 ex = cast(CatExp)ex.e1; 2365 elems.shift(array_toDarray(ex.e2.type, toElem(ex.e2, irs))); 2366 } while (ex.e1.op == TOK.concatenate); 2367 elems.shift(array_toDarray(ex.e1.type, toElem(ex.e1, irs))); 2368 2369 // We can't use ExpressionsToStaticArray because each exp needs 2370 // to have array_toDarray called on it first, as some might be 2371 // single elements instead of arrays. 2372 Symbol *sdata; 2373 elem *earr = ElemsToStaticArray(ce.loc, ce.type, &elems, &sdata); 2374 2375 elem *ep = el_pair(TYdarray, el_long(TYsize_t, elems.dim), el_ptr(sdata)); 2376 if (config.exe == EX_WIN64) 2377 ep = addressElem(ep, Type.tvoid.arrayOf()); 2378 ep = el_param(ep, getTypeInfo(ce.loc, ta, irs)); 2379 e = el_bin(OPcall, TYdarray, el_var(getRtlsym(RTLSYM_ARRAYCATNTX)), ep); 2380 toTraceGC(irs, e, ce.loc); 2381 e = el_combine(earr, e); 2382 } 2383 else 2384 { 2385 elem *e1 = eval_Darray(ce.e1); 2386 elem *e2 = eval_Darray(ce.e2); 2387 elem *ep = el_params(e2, e1, getTypeInfo(ce.loc, ta, irs), null); 2388 e = el_bin(OPcall, TYdarray, el_var(getRtlsym(RTLSYM_ARRAYCATT)), ep); 2389 toTraceGC(irs, e, ce.loc); 2390 } 2391 elem_setLoc(e,ce.loc); 2392 result = e; 2393 } 2394 2395 /*************************************** 2396 */ 2397 2398 override void visit(MulExp e) 2399 { 2400 result = toElemBin(e, OPmul); 2401 } 2402 2403 /************************************ 2404 */ 2405 2406 override void visit(DivExp e) 2407 { 2408 result = toElemBin(e, OPdiv); 2409 } 2410 2411 /*************************************** 2412 */ 2413 2414 override void visit(ModExp e) 2415 { 2416 result = toElemBin(e, OPmod); 2417 } 2418 2419 /*************************************** 2420 */ 2421 2422 override void visit(CmpExp ce) 2423 { 2424 //printf("CmpExp.toElem() %s\n", ce.toChars()); 2425 2426 OPER eop; 2427 Type t1 = ce.e1.type.toBasetype(); 2428 Type t2 = ce.e2.type.toBasetype(); 2429 2430 switch (ce.op) 2431 { 2432 case TOK.lessThan: eop = OPlt; break; 2433 case TOK.greaterThan: eop = OPgt; break; 2434 case TOK.lessOrEqual: eop = OPle; break; 2435 case TOK.greaterOrEqual: eop = OPge; break; 2436 case TOK.equal: eop = OPeqeq; break; 2437 case TOK.notEqual: eop = OPne; break; 2438 2439 default: 2440 printf("%s\n", ce.toChars()); 2441 assert(0); 2442 } 2443 if (!t1.isfloating()) 2444 { 2445 // Convert from floating point compare to equivalent 2446 // integral compare 2447 eop = cast(OPER)rel_integral(eop); 2448 } 2449 elem *e; 2450 if (cast(int)eop > 1 && t1.ty == Tclass && t2.ty == Tclass) 2451 { 2452 // Should have already been lowered 2453 assert(0); 2454 } 2455 else if (cast(int)eop > 1 && 2456 (t1.ty == Tarray || t1.ty == Tsarray) && 2457 (t2.ty == Tarray || t2.ty == Tsarray)) 2458 { 2459 // This codepath was replaced by lowering during semantic 2460 // to object.__cmp in druntime. 2461 assert(0); 2462 } 2463 else 2464 { 2465 if (cast(int)eop <= 1) 2466 { 2467 /* The result is determinate, create: 2468 * (e1 , e2) , eop 2469 */ 2470 e = toElemBin(ce,OPcomma); 2471 e = el_bin(OPcomma,e.Ety,e,el_long(e.Ety,cast(int)eop)); 2472 } 2473 else 2474 e = toElemBin(ce,eop); 2475 } 2476 result = e; 2477 } 2478 2479 override void visit(EqualExp ee) 2480 { 2481 //printf("EqualExp.toElem() %s\n", ee.toChars()); 2482 2483 Type t1 = ee.e1.type.toBasetype(); 2484 Type t2 = ee.e2.type.toBasetype(); 2485 2486 OPER eop; 2487 switch (ee.op) 2488 { 2489 case TOK.equal: eop = OPeqeq; break; 2490 case TOK.notEqual: eop = OPne; break; 2491 default: 2492 printf("%s\n", ee.toChars()); 2493 assert(0); 2494 } 2495 2496 //printf("EqualExp.toElem()\n"); 2497 elem *e; 2498 if (t1.ty == Tstruct) 2499 { 2500 // Rewritten to IdentityExp or memberwise-compare 2501 assert(0); 2502 } 2503 else if ((t1.ty == Tarray || t1.ty == Tsarray) && 2504 (t2.ty == Tarray || t2.ty == Tsarray)) 2505 { 2506 Type telement = t1.nextOf().toBasetype(); 2507 Type telement2 = t2.nextOf().toBasetype(); 2508 2509 if ((telement.isintegral() || telement.ty == Tvoid) && telement.ty == telement2.ty) 2510 { 2511 // Optimize comparisons of arrays of basic types 2512 // For arrays of integers/characters, and void[], 2513 // replace druntime call with: 2514 // For a==b: a.length==b.length && (a.length == 0 || memcmp(a.ptr, b.ptr, size)==0) 2515 // For a!=b: a.length!=b.length || (a.length != 0 || memcmp(a.ptr, b.ptr, size)!=0) 2516 // size is a.length*sizeof(a[0]) for dynamic arrays, or sizeof(a) for static arrays. 2517 2518 elem* earr1 = toElem(ee.e1, irs); 2519 elem* earr2 = toElem(ee.e2, irs); 2520 elem* eptr1, eptr2; // Pointer to data, to pass to memcmp 2521 elem* elen1, elen2; // Length, for comparison 2522 elem* esiz1, esiz2; // Data size, to pass to memcmp 2523 d_uns64 sz = telement.size(); // Size of one element 2524 2525 if (t1.ty == Tarray) 2526 { 2527 elen1 = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, el_same(&earr1)); 2528 esiz1 = el_bin(OPmul, TYsize_t, el_same(&elen1), el_long(TYsize_t, sz)); 2529 eptr1 = array_toPtr(t1, el_same(&earr1)); 2530 } 2531 else 2532 { 2533 elen1 = el_long(TYsize_t, (cast(TypeSArray)t1).dim.toInteger()); 2534 esiz1 = el_long(TYsize_t, t1.size()); 2535 earr1 = addressElem(earr1, t1); 2536 eptr1 = el_same(&earr1); 2537 } 2538 2539 if (t2.ty == Tarray) 2540 { 2541 elen2 = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, el_same(&earr2)); 2542 esiz2 = el_bin(OPmul, TYsize_t, el_same(&elen2), el_long(TYsize_t, sz)); 2543 eptr2 = array_toPtr(t2, el_same(&earr2)); 2544 } 2545 else 2546 { 2547 elen2 = el_long(TYsize_t, (cast(TypeSArray)t2).dim.toInteger()); 2548 esiz2 = el_long(TYsize_t, t2.size()); 2549 earr2 = addressElem(earr2, t2); 2550 eptr2 = el_same(&earr2); 2551 } 2552 2553 elem *esize = t2.ty == Tsarray ? esiz2 : esiz1; 2554 2555 e = el_param(eptr1, eptr2); 2556 e = el_bin(OPmemcmp, TYint, e, esize); 2557 e = el_bin(eop, TYint, e, el_long(TYint, 0)); 2558 2559 elem *elen = t2.ty == Tsarray ? elen2 : elen1; 2560 elem *esizecheck = el_bin(eop, TYint, el_same(&elen), el_long(TYsize_t, 0)); 2561 e = el_bin(ee.op == TOK.equal ? OPoror : OPandand, TYint, esizecheck, e); 2562 2563 if (t1.ty == Tsarray && t2.ty == Tsarray) 2564 assert(t1.size() == t2.size()); 2565 else 2566 { 2567 elem *elencmp = el_bin(eop, TYint, elen1, elen2); 2568 e = el_bin(ee.op == TOK.equal ? OPandand : OPoror, TYint, elencmp, e); 2569 } 2570 2571 // Ensure left-to-right order of evaluation 2572 e = el_combine(earr2, e); 2573 e = el_combine(earr1, e); 2574 elem_setLoc(e, ee.loc); 2575 result = e; 2576 return; 2577 } 2578 2579 elem *ea1 = eval_Darray(ee.e1); 2580 elem *ea2 = eval_Darray(ee.e2); 2581 2582 elem *ep = el_params(getTypeInfo(ee.loc, telement.arrayOf(), irs), 2583 ea2, ea1, null); 2584 int rtlfunc = RTLSYM_ARRAYEQ2; 2585 e = el_bin(OPcall, TYint, el_var(getRtlsym(rtlfunc)), ep); 2586 if (ee.op == TOK.notEqual) 2587 e = el_bin(OPxor, TYint, e, el_long(TYint, 1)); 2588 elem_setLoc(e,ee.loc); 2589 } 2590 else if (t1.ty == Taarray && t2.ty == Taarray) 2591 { 2592 TypeAArray taa = cast(TypeAArray)t1; 2593 Symbol *s = aaGetSymbol(taa, "Equal", 0); 2594 elem *ti = getTypeInfo(ee.loc, taa, irs); 2595 elem *ea1 = toElem(ee.e1, irs); 2596 elem *ea2 = toElem(ee.e2, irs); 2597 // aaEqual(ti, e1, e2) 2598 elem *ep = el_params(ea2, ea1, ti, null); 2599 e = el_bin(OPcall, TYnptr, el_var(s), ep); 2600 if (ee.op == TOK.notEqual) 2601 e = el_bin(OPxor, TYint, e, el_long(TYint, 1)); 2602 elem_setLoc(e, ee.loc); 2603 result = e; 2604 return; 2605 } 2606 else 2607 e = toElemBin(ee, eop); 2608 result = e; 2609 } 2610 2611 override void visit(IdentityExp ie) 2612 { 2613 Type t1 = ie.e1.type.toBasetype(); 2614 Type t2 = ie.e2.type.toBasetype(); 2615 2616 OPER eop; 2617 switch (ie.op) 2618 { 2619 case TOK.identity: eop = OPeqeq; break; 2620 case TOK.notIdentity: eop = OPne; break; 2621 default: 2622 printf("%s\n", ie.toChars()); 2623 assert(0); 2624 } 2625 2626 //printf("IdentityExp.toElem() %s\n", ie.toChars()); 2627 2628 /* Fix Issue 18746 : https://issues.dlang.org/show_bug.cgi?id=18746 2629 * Before skipping the comparison for empty structs 2630 * it is necessary to check whether the expressions involved 2631 * have any sideeffects 2632 */ 2633 2634 const canSkipCompare = isTrivialExp(ie.e1) && isTrivialExp(ie.e2); 2635 elem *e; 2636 if (t1.ty == Tstruct && (cast(TypeStruct)t1).sym.fields.dim == 0 && canSkipCompare) 2637 { 2638 // we can skip the compare if the structs are empty 2639 e = el_long(TYbool, ie.op == TOK.identity); 2640 } 2641 else if (t1.ty == Tstruct || t1.isfloating()) 2642 { 2643 // Do bit compare of struct's 2644 elem *es1 = toElem(ie.e1, irs); 2645 es1 = addressElem(es1, ie.e1.type); 2646 elem *es2 = toElem(ie.e2, irs); 2647 es2 = addressElem(es2, ie.e2.type); 2648 e = el_param(es1, es2); 2649 elem *ecount = el_long(TYsize_t, t1.size()); 2650 e = el_bin(OPmemcmp, TYint, e, ecount); 2651 e = el_bin(eop, TYint, e, el_long(TYint, 0)); 2652 elem_setLoc(e, ie.loc); 2653 } 2654 else if ((t1.ty == Tarray || t1.ty == Tsarray) && 2655 (t2.ty == Tarray || t2.ty == Tsarray)) 2656 { 2657 2658 elem *ea1 = toElem(ie.e1, irs); 2659 ea1 = array_toDarray(t1, ea1); 2660 elem *ea2 = toElem(ie.e2, irs); 2661 ea2 = array_toDarray(t2, ea2); 2662 2663 e = el_bin(eop, totym(ie.type), ea1, ea2); 2664 elem_setLoc(e, ie.loc); 2665 } 2666 else 2667 e = toElemBin(ie, eop); 2668 2669 result = e; 2670 } 2671 2672 /*************************************** 2673 */ 2674 2675 override void visit(InExp ie) 2676 { 2677 elem *key = toElem(ie.e1, irs); 2678 elem *aa = toElem(ie.e2, irs); 2679 TypeAArray taa = cast(TypeAArray)ie.e2.type.toBasetype(); 2680 2681 // aaInX(aa, keyti, key); 2682 key = addressElem(key, ie.e1.type); 2683 Symbol *s = aaGetSymbol(taa, "InX", 0); 2684 elem *keyti = getTypeInfo(ie.loc, taa.index, irs); 2685 elem *ep = el_params(key, keyti, aa, null); 2686 elem *e = el_bin(OPcall, totym(ie.type), el_var(s), ep); 2687 2688 elem_setLoc(e, ie.loc); 2689 result = e; 2690 } 2691 2692 /*************************************** 2693 */ 2694 2695 override void visit(RemoveExp re) 2696 { 2697 auto taa = re.e1.type.toBasetype().isTypeAArray(); 2698 assert(taa); 2699 elem *ea = toElem(re.e1, irs); 2700 elem *ekey = toElem(re.e2, irs); 2701 2702 ekey = addressElem(ekey, re.e2.type); 2703 Symbol *s = aaGetSymbol(taa, "DelX", 0); 2704 elem *keyti = getTypeInfo(re.loc, taa.index, irs); 2705 elem *ep = el_params(ekey, keyti, ea, null); 2706 elem *e = el_bin(OPcall, TYnptr, el_var(s), ep); 2707 2708 elem_setLoc(e, re.loc); 2709 result = e; 2710 } 2711 2712 /*************************************** 2713 */ 2714 2715 override void visit(AssignExp ae) 2716 { 2717 version (none) 2718 { 2719 if (ae.op == TOK.blit) printf("BlitExp.toElem('%s')\n", ae.toChars()); 2720 if (ae.op == TOK.assign) printf("AssignExp.toElem('%s')\n", ae.toChars()); 2721 if (ae.op == TOK.construct) printf("ConstructExp.toElem('%s')\n", ae.toChars()); 2722 } 2723 2724 void setResult(elem* e) 2725 { 2726 elem_setLoc(e, ae.loc); 2727 result = e; 2728 } 2729 2730 Type t1b = ae.e1.type.toBasetype(); 2731 2732 // Look for array.length = n 2733 if (auto ale = ae.e1.isArrayLengthExp()) 2734 { 2735 assert(0, "This case should have been rewritten to `_d_arraysetlengthT` in the semantic phase"); 2736 } 2737 2738 // Look for array[]=n 2739 if (auto are = ae.e1.isSliceExp()) 2740 { 2741 Type t1 = t1b; 2742 Type ta = are.e1.type.toBasetype(); 2743 2744 // which we do if the 'next' types match 2745 if (ae.memset & MemorySet.blockAssign) 2746 { 2747 // Do a memset for array[]=v 2748 //printf("Lpair %s\n", ae.toChars()); 2749 Type tb = ta.nextOf().toBasetype(); 2750 uint sz = cast(uint)tb.size(); 2751 2752 elem *n1 = toElem(are.e1, irs); 2753 elem *elwr = are.lwr ? toElem(are.lwr, irs) : null; 2754 elem *eupr = are.upr ? toElem(are.upr, irs) : null; 2755 2756 elem *n1x = n1; 2757 2758 elem *enbytes; 2759 elem *einit; 2760 // Look for array[]=n 2761 if (auto ts = ta.isTypeSArray()) 2762 { 2763 n1 = array_toPtr(ta, n1); 2764 enbytes = toElem(ts.dim, irs); 2765 n1x = n1; 2766 n1 = el_same(&n1x); 2767 einit = resolveLengthVar(are.lengthVar, &n1, ta); 2768 } 2769 else if (ta.ty == Tarray) 2770 { 2771 n1 = el_same(&n1x); 2772 einit = resolveLengthVar(are.lengthVar, &n1, ta); 2773 enbytes = el_copytree(n1); 2774 n1 = array_toPtr(ta, n1); 2775 enbytes = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, enbytes); 2776 } 2777 else if (ta.ty == Tpointer) 2778 { 2779 n1 = el_same(&n1x); 2780 enbytes = el_long(TYsize_t, -1); // largest possible index 2781 einit = null; 2782 } 2783 2784 // Enforce order of evaluation of n1[elwr..eupr] as n1,elwr,eupr 2785 elem *elwrx = elwr; 2786 if (elwr) elwr = el_same(&elwrx); 2787 elem *euprx = eupr; 2788 if (eupr) eupr = el_same(&euprx); 2789 2790 version (none) 2791 { 2792 printf("sz = %d\n", sz); 2793 printf("n1x\n"); elem_print(n1x); 2794 printf("einit\n"); elem_print(einit); 2795 printf("elwrx\n"); elem_print(elwrx); 2796 printf("euprx\n"); elem_print(euprx); 2797 printf("n1\n"); elem_print(n1); 2798 printf("elwr\n"); elem_print(elwr); 2799 printf("eupr\n"); elem_print(eupr); 2800 printf("enbytes\n"); elem_print(enbytes); 2801 } 2802 einit = el_combine(n1x, einit); 2803 einit = el_combine(einit, elwrx); 2804 einit = el_combine(einit, euprx); 2805 2806 elem *evalue = toElem(ae.e2, irs); 2807 2808 version (none) 2809 { 2810 printf("n1\n"); elem_print(n1); 2811 printf("enbytes\n"); elem_print(enbytes); 2812 } 2813 2814 if (irs.arrayBoundsCheck() && eupr && ta.ty != Tpointer) 2815 { 2816 assert(elwr); 2817 elem *enbytesx = enbytes; 2818 enbytes = el_same(&enbytesx); 2819 elem *c1 = el_bin(OPle, TYint, el_copytree(eupr), enbytesx); 2820 elem *c2 = el_bin(OPle, TYint, el_copytree(elwr), el_copytree(eupr)); 2821 c1 = el_bin(OPandand, TYint, c1, c2); 2822 2823 // Construct: (c1 || arrayBoundsError) 2824 auto ea = buildArrayBoundsError(irs, ae.loc, el_copytree(elwr), el_copytree(eupr), el_copytree(enbytesx)); 2825 elem *eb = el_bin(OPoror,TYvoid,c1,ea); 2826 einit = el_combine(einit, eb); 2827 } 2828 2829 elem *elength; 2830 if (elwr) 2831 { 2832 el_free(enbytes); 2833 elem *elwr2 = el_copytree(elwr); 2834 elwr2 = el_bin(OPmul, TYsize_t, elwr2, el_long(TYsize_t, sz)); 2835 n1 = el_bin(OPadd, TYnptr, n1, elwr2); 2836 enbytes = el_bin(OPmin, TYsize_t, eupr, elwr); 2837 elength = el_copytree(enbytes); 2838 } 2839 else 2840 elength = el_copytree(enbytes); 2841 elem* e = setArray(are.e1, n1, enbytes, tb, evalue, irs, ae.op); 2842 e = el_pair(TYdarray, elength, e); 2843 e = el_combine(einit, e); 2844 //elem_print(e); 2845 return setResult(e); 2846 } 2847 else 2848 { 2849 /* It's array1[]=array2[] 2850 * which is a memcpy 2851 */ 2852 elem *eto = toElem(ae.e1, irs); 2853 elem *efrom = toElem(ae.e2, irs); 2854 2855 uint size = cast(uint)t1.nextOf().size(); 2856 elem *esize = el_long(TYsize_t, size); 2857 2858 /* Determine if we need to do postblit 2859 */ 2860 bool postblit = false; 2861 if (needsPostblit(t1.nextOf()) && 2862 (ae.e2.op == TOK.slice && (cast(UnaExp)ae.e2).e1.isLvalue() || 2863 ae.e2.op == TOK.cast_ && (cast(UnaExp)ae.e2).e1.isLvalue() || 2864 ae.e2.op != TOK.slice && ae.e2.isLvalue())) 2865 { 2866 postblit = true; 2867 } 2868 bool destructor = needsDtor(t1.nextOf()) !is null; 2869 2870 assert(ae.e2.type.ty != Tpointer); 2871 2872 if (!postblit && !destructor) 2873 { 2874 elem *ex = el_same(&eto); 2875 2876 /* Returns: length of array ex 2877 */ 2878 static elem *getDotLength(IRState* irs, elem *eto, elem *ex) 2879 { 2880 if (eto.Eoper == OPpair && 2881 eto.EV.E1.Eoper == OPconst) 2882 { 2883 // It's a constant, so just pull it from eto 2884 return el_copytree(eto.EV.E1); 2885 } 2886 else 2887 { 2888 // It's not a constant, so pull it from the dynamic array 2889 return el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, el_copytree(ex)); 2890 } 2891 } 2892 2893 auto elen = getDotLength(irs, eto, ex); 2894 auto nbytes = el_bin(OPmul, TYsize_t, elen, esize); // number of bytes to memcpy 2895 auto epto = array_toPtr(ae.e1.type, ex); 2896 2897 elem *epfr; 2898 elem *echeck; 2899 if (irs.arrayBoundsCheck()) // check array lengths match and do not overlap 2900 { 2901 auto ey = el_same(&efrom); 2902 auto eleny = getDotLength(irs, efrom, ey); 2903 epfr = array_toPtr(ae.e2.type, ey); 2904 2905 // length check: (eleny == elen) 2906 auto c = el_bin(OPeqeq, TYint, eleny, el_copytree(elen)); 2907 2908 /* Don't check overlap if epto and epfr point to different symbols 2909 */ 2910 if (!(epto.Eoper == OPaddr && epto.EV.E1.Eoper == OPvar && 2911 epfr.Eoper == OPaddr && epfr.EV.E1.Eoper == OPvar && 2912 epto.EV.E1.EV.Vsym != epfr.EV.E1.EV.Vsym)) 2913 { 2914 // Add overlap check (c && (px + nbytes <= py || py + nbytes <= px)) 2915 auto c2 = el_bin(OPle, TYint, el_bin(OPadd, TYsize_t, el_copytree(epto), el_copytree(nbytes)), el_copytree(epfr)); 2916 auto c3 = el_bin(OPle, TYint, el_bin(OPadd, TYsize_t, el_copytree(epfr), el_copytree(nbytes)), el_copytree(epto)); 2917 c = el_bin(OPandand, TYint, c, el_bin(OPoror, TYint, c2, c3)); 2918 } 2919 2920 // Construct: (c || arrayBoundsError) 2921 echeck = el_bin(OPoror, TYvoid, c, buildArrayBoundsError(irs, ae.loc, null, el_copytree(eleny), el_copytree(elen))); 2922 } 2923 else 2924 { 2925 epfr = array_toPtr(ae.e2.type, efrom); 2926 efrom = null; 2927 echeck = null; 2928 } 2929 2930 /* Construct: 2931 * memcpy(ex.ptr, ey.ptr, nbytes)[0..elen] 2932 */ 2933 elem* e = el_params(nbytes, epfr, epto, null); 2934 e = el_bin(OPcall,TYnptr,el_var(getRtlsym(RTLSYM_MEMCPY)),e); 2935 e = el_pair(eto.Ety, el_copytree(elen), e); 2936 2937 /* Combine: eto, efrom, echeck, e 2938 */ 2939 e = el_combine(el_combine(eto, efrom), el_combine(echeck, e)); 2940 return setResult(e); 2941 } 2942 else if ((postblit || destructor) && ae.op != TOK.blit) 2943 { 2944 /* Generate: 2945 * _d_arrayassign(ti, efrom, eto) 2946 * or: 2947 * _d_arrayctor(ti, efrom, eto) 2948 */ 2949 el_free(esize); 2950 elem *eti = getTypeInfo(ae.e1.loc, t1.nextOf().toBasetype(), irs); 2951 if (config.exe == EX_WIN64) 2952 { 2953 eto = addressElem(eto, Type.tvoid.arrayOf()); 2954 efrom = addressElem(efrom, Type.tvoid.arrayOf()); 2955 } 2956 elem *ep = el_params(eto, efrom, eti, null); 2957 int rtl = (ae.op == TOK.construct) ? RTLSYM_ARRAYCTOR : RTLSYM_ARRAYASSIGN; 2958 elem* e = el_bin(OPcall, totym(ae.type), el_var(getRtlsym(rtl)), ep); 2959 return setResult(e); 2960 } 2961 else 2962 { 2963 // Generate: 2964 // _d_arraycopy(eto, efrom, esize) 2965 2966 if (config.exe == EX_WIN64) 2967 { 2968 eto = addressElem(eto, Type.tvoid.arrayOf()); 2969 efrom = addressElem(efrom, Type.tvoid.arrayOf()); 2970 } 2971 elem *ep = el_params(eto, efrom, esize, null); 2972 elem* e = el_bin(OPcall, totym(ae.type), el_var(getRtlsym(RTLSYM_ARRAYCOPY)), ep); 2973 return setResult(e); 2974 } 2975 } 2976 assert(0); 2977 } 2978 2979 /* Look for initialization of an `out` or `ref` variable 2980 */ 2981 if (ae.memset & MemorySet.referenceInit) 2982 { 2983 assert(ae.op == TOK.construct || ae.op == TOK.blit); 2984 auto ve = ae.e1.isVarExp(); 2985 assert(ve); 2986 assert(ve.var.storage_class & (STC.out_ | STC.ref_)); 2987 2988 // It'll be initialized to an address 2989 elem* e = toElem(ae.e2, irs); 2990 e = addressElem(e, ae.e2.type); 2991 elem *es = toElem(ae.e1, irs); 2992 if (es.Eoper == OPind) 2993 es = es.EV.E1; 2994 else 2995 es = el_una(OPaddr, TYnptr, es); 2996 es.Ety = TYnptr; 2997 e = el_bin(OPeq, TYnptr, es, e); 2998 assert(!(t1b.ty == Tstruct && ae.e2.op == TOK.int64)); 2999 3000 return setResult(e); 3001 } 3002 3003 tym_t tym = totym(ae.type); 3004 elem *e1 = toElem(ae.e1, irs); 3005 3006 elem *e1x; 3007 3008 void setResult2(elem* e) 3009 { 3010 return setResult(el_combine(e, e1x)); 3011 } 3012 3013 // Create a reference to e1. 3014 if (e1.Eoper == OPvar) 3015 e1x = el_copytree(e1); 3016 else 3017 { 3018 /* Rewrite to: 3019 * e1 = *((tmp = &e1), tmp) 3020 * e1x = *tmp 3021 */ 3022 e1 = addressElem(e1, null); 3023 e1x = el_same(&e1); 3024 e1 = el_una(OPind, tym, e1); 3025 if (tybasic(tym) == TYstruct) 3026 e1.ET = Type_toCtype(ae.e1.type); 3027 e1x = el_una(OPind, tym, e1x); 3028 if (tybasic(tym) == TYstruct) 3029 e1x.ET = Type_toCtype(ae.e1.type); 3030 //printf("e1 = \n"); elem_print(e1); 3031 //printf("e1x = \n"); elem_print(e1x); 3032 } 3033 3034 // inlining may generate lazy variable initialization 3035 if (auto ve = ae.e1.isVarExp()) 3036 if (ve.var.storage_class & STC.lazy_) 3037 { 3038 assert(ae.op == TOK.construct || ae.op == TOK.blit); 3039 elem* e = el_bin(OPeq, tym, e1, toElem(ae.e2, irs)); 3040 return setResult2(e); 3041 } 3042 3043 /* This will work if we can distinguish an assignment from 3044 * an initialization of the lvalue. It'll work if the latter. 3045 * If the former, because of aliasing of the return value with 3046 * function arguments, it'll fail. 3047 */ 3048 if (ae.op == TOK.construct && ae.e2.op == TOK.call) 3049 { 3050 CallExp ce = cast(CallExp)ae.e2; 3051 TypeFunction tf = cast(TypeFunction)ce.e1.type.toBasetype(); 3052 if (tf.ty == Tfunction && retStyle(tf, ce.f && ce.f.needThis()) == RET.stack) 3053 { 3054 elem *ehidden = e1; 3055 ehidden = el_una(OPaddr, TYnptr, ehidden); 3056 assert(!irs.ehidden); 3057 irs.ehidden = ehidden; 3058 elem* e = toElem(ae.e2, irs); 3059 return setResult2(e); 3060 } 3061 3062 /* Look for: 3063 * v = structliteral.ctor(args) 3064 * and have the structliteral write into v, rather than create a temporary 3065 * and copy the temporary into v 3066 */ 3067 if (e1.Eoper == OPvar && // no closure variables https://issues.dlang.org/show_bug.cgi?id=17622 3068 ae.e1.op == TOK.variable && ce.e1.op == TOK.dotVariable) 3069 { 3070 auto dve = cast(DotVarExp)ce.e1; 3071 auto fd = dve.var.isFuncDeclaration(); 3072 if (fd && fd.isCtorDeclaration()) 3073 { 3074 if (auto sle = dve.e1.isStructLiteralExp()) 3075 { 3076 sle.sym = toSymbol((cast(VarExp)ae.e1).var); 3077 elem* e = toElem(ae.e2, irs); 3078 return setResult2(e); 3079 } 3080 } 3081 } 3082 } 3083 3084 //if (ae.op == TOK.construct) printf("construct\n"); 3085 if (auto t1s = t1b.isTypeStruct()) 3086 { 3087 if (ae.e2.op == TOK.int64) 3088 { 3089 assert(ae.op == TOK.blit); 3090 3091 /* Implement: 3092 * (struct = 0) 3093 * with: 3094 * memset(&struct, 0, struct.sizeof) 3095 */ 3096 uint sz = cast(uint)ae.e1.type.size(); 3097 3098 elem *el = e1; 3099 elem *enbytes = el_long(TYsize_t, sz); 3100 elem *evalue = el_long(TYsize_t, 0); 3101 3102 el = el_una(OPaddr, TYnptr, el); 3103 elem* e = el_param(enbytes, evalue); 3104 e = el_bin(OPmemset,TYnptr,el,e); 3105 return setResult2(e); 3106 } 3107 3108 //printf("toElemBin() '%s'\n", ae.toChars()); 3109 3110 if (auto sle = ae.e2.isStructLiteralExp()) 3111 { 3112 auto ex = e1.Eoper == OPind ? e1.EV.E1 : e1; 3113 if (ex.Eoper == OPvar && ex.EV.Voffset == 0 && 3114 (ae.op == TOK.construct || ae.op == TOK.blit)) 3115 { 3116 elem* e = toElemStructLit(sle, irs, ae.op, ex.EV.Vsym, true); 3117 el_free(e1); 3118 return setResult2(e); 3119 } 3120 } 3121 3122 /* Implement: 3123 * (struct = struct) 3124 */ 3125 elem *e2 = toElem(ae.e2, irs); 3126 3127 elem* e = elAssign(e1, e2, ae.e1.type, null); 3128 return setResult2(e); 3129 } 3130 else if (t1b.ty == Tsarray) 3131 { 3132 if (ae.op == TOK.blit && ae.e2.op == TOK.int64) 3133 { 3134 /* Implement: 3135 * (sarray = 0) 3136 * with: 3137 * memset(&sarray, 0, struct.sizeof) 3138 */ 3139 elem *ey = null; 3140 targ_size_t sz = ae.e1.type.size(); 3141 3142 elem *el = e1; 3143 elem *enbytes = el_long(TYsize_t, sz); 3144 elem *evalue = el_long(TYsize_t, 0); 3145 3146 el = el_una(OPaddr, TYnptr, el); 3147 elem* e = el_param(enbytes, evalue); 3148 e = el_bin(OPmemset,TYnptr,el,e); 3149 e = el_combine(ey, e); 3150 return setResult2(e); 3151 } 3152 3153 /* Implement: 3154 * (sarray = sarray) 3155 */ 3156 assert(ae.e2.type.toBasetype().ty == Tsarray); 3157 3158 bool postblit = needsPostblit(t1b.nextOf()) !is null; 3159 bool destructor = needsDtor(t1b.nextOf()) !is null; 3160 3161 /* Optimize static array assignment with array literal. 3162 * Rewrite: 3163 * e1 = [a, b, ...]; 3164 * as: 3165 * e1[0] = a, e1[1] = b, ...; 3166 * 3167 * If the same values are contiguous, that will be rewritten 3168 * to block assignment. 3169 * Rewrite: 3170 * e1 = [x, a, a, b, ...]; 3171 * as: 3172 * e1[0] = x, e1[1..2] = a, e1[3] = b, ...; 3173 */ 3174 if (ae.op == TOK.construct && // https://issues.dlang.org/show_bug.cgi?id=11238 3175 // avoid aliasing issue 3176 ae.e2.op == TOK.arrayLiteral) 3177 { 3178 ArrayLiteralExp ale = cast(ArrayLiteralExp)ae.e2; 3179 elem* e; 3180 if (ale.elements.dim == 0) 3181 { 3182 e = e1; 3183 } 3184 else 3185 { 3186 Symbol *stmp = symbol_genauto(TYnptr); 3187 e1 = addressElem(e1, t1b); 3188 e1 = el_bin(OPeq, TYnptr, el_var(stmp), e1); 3189 3190 // Eliminate _d_arrayliteralTX call in ae.e2. 3191 e = ExpressionsToStaticArray(ale.loc, ale.elements, &stmp, 0, ale.basis); 3192 e = el_combine(e1, e); 3193 } 3194 return setResult2(e); 3195 } 3196 3197 /* https://issues.dlang.org/show_bug.cgi?id=13661 3198 * Even if the elements in rhs are all rvalues and 3199 * don't have to call postblits, this assignment should call 3200 * destructors on old assigned elements. 3201 */ 3202 bool lvalueElem = false; 3203 if (ae.e2.op == TOK.slice && (cast(UnaExp)ae.e2).e1.isLvalue() || 3204 ae.e2.op == TOK.cast_ && (cast(UnaExp)ae.e2).e1.isLvalue() || 3205 ae.e2.op != TOK.slice && ae.e2.isLvalue()) 3206 { 3207 lvalueElem = true; 3208 } 3209 3210 elem *e2 = toElem(ae.e2, irs); 3211 3212 if (!postblit && !destructor || 3213 ae.op == TOK.construct && !lvalueElem && postblit || 3214 ae.op == TOK.blit || 3215 type_size(e1.ET) == 0) 3216 { 3217 elem* e = elAssign(e1, e2, ae.e1.type, null); 3218 return setResult2(e); 3219 } 3220 else if (ae.op == TOK.construct) 3221 { 3222 e1 = sarray_toDarray(ae.e1.loc, ae.e1.type, null, e1); 3223 e2 = sarray_toDarray(ae.e2.loc, ae.e2.type, null, e2); 3224 3225 /* Generate: 3226 * _d_arrayctor(ti, e2, e1) 3227 */ 3228 elem *eti = getTypeInfo(ae.e1.loc, t1b.nextOf().toBasetype(), irs); 3229 if (config.exe == EX_WIN64) 3230 { 3231 e1 = addressElem(e1, Type.tvoid.arrayOf()); 3232 e2 = addressElem(e2, Type.tvoid.arrayOf()); 3233 } 3234 elem *ep = el_params(e1, e2, eti, null); 3235 elem* e = el_bin(OPcall, TYdarray, el_var(getRtlsym(RTLSYM_ARRAYCTOR)), ep); 3236 return setResult2(e); 3237 } 3238 else 3239 { 3240 e1 = sarray_toDarray(ae.e1.loc, ae.e1.type, null, e1); 3241 e2 = sarray_toDarray(ae.e2.loc, ae.e2.type, null, e2); 3242 3243 Symbol *stmp = symbol_genauto(Type_toCtype(t1b.nextOf())); 3244 elem *etmp = el_una(OPaddr, TYnptr, el_var(stmp)); 3245 3246 /* Generate: 3247 * _d_arrayassign_l(ti, e2, e1, etmp) 3248 * or: 3249 * _d_arrayassign_r(ti, e2, e1, etmp) 3250 */ 3251 elem *eti = getTypeInfo(ae.e1.loc, t1b.nextOf().toBasetype(), irs); 3252 if (config.exe == EX_WIN64) 3253 { 3254 e1 = addressElem(e1, Type.tvoid.arrayOf()); 3255 e2 = addressElem(e2, Type.tvoid.arrayOf()); 3256 } 3257 elem *ep = el_params(etmp, e1, e2, eti, null); 3258 int rtl = lvalueElem ? RTLSYM_ARRAYASSIGN_L : RTLSYM_ARRAYASSIGN_R; 3259 elem* e = el_bin(OPcall, TYdarray, el_var(getRtlsym(rtl)), ep); 3260 return setResult2(e); 3261 } 3262 } 3263 else 3264 { 3265 elem* e = el_bin(OPeq, tym, e1, toElem(ae.e2, irs)); 3266 return setResult2(e); 3267 } 3268 assert(0); 3269 } 3270 3271 /*************************************** 3272 */ 3273 3274 override void visit(AddAssignExp e) 3275 { 3276 //printf("AddAssignExp.toElem() %s\n", e.toChars()); 3277 result = toElemBinAssign(e, OPaddass); 3278 } 3279 3280 3281 /*************************************** 3282 */ 3283 3284 override void visit(MinAssignExp e) 3285 { 3286 result = toElemBinAssign(e, OPminass); 3287 } 3288 3289 /*************************************** 3290 */ 3291 3292 override void visit(CatAssignExp ce) 3293 { 3294 //printf("CatAssignExp.toElem('%s')\n", ce.toChars()); 3295 elem *e; 3296 Type tb1 = ce.e1.type.toBasetype(); 3297 Type tb2 = ce.e2.type.toBasetype(); 3298 assert(tb1.ty == Tarray); 3299 Type tb1n = tb1.nextOf().toBasetype(); 3300 3301 elem *e1 = toElem(ce.e1, irs); 3302 elem *e2 = toElem(ce.e2, irs); 3303 3304 switch (ce.op) 3305 { 3306 case TOK.concatenateDcharAssign: 3307 { 3308 // Append dchar to char[] or wchar[] 3309 assert(tb2.ty == Tdchar && 3310 (tb1n.ty == Tchar || tb1n.ty == Twchar)); 3311 3312 e1 = el_una(OPaddr, TYnptr, e1); 3313 3314 elem *ep = el_params(e2, e1, null); 3315 int rtl = (tb1.nextOf().ty == Tchar) 3316 ? RTLSYM_ARRAYAPPENDCD 3317 : RTLSYM_ARRAYAPPENDWD; 3318 e = el_bin(OPcall, TYdarray, el_var(getRtlsym(rtl)), ep); 3319 toTraceGC(irs, e, ce.loc); 3320 elem_setLoc(e, ce.loc); 3321 break; 3322 } 3323 3324 case TOK.concatenateAssign: 3325 { 3326 // Append array 3327 assert(tb2.ty == Tarray || tb2.ty == Tsarray); 3328 3329 assert(tb1n.equals(tb2.nextOf().toBasetype())); 3330 3331 e1 = el_una(OPaddr, TYnptr, e1); 3332 if (config.exe == EX_WIN64) 3333 e2 = addressElem(e2, tb2, true); 3334 else 3335 e2 = useOPstrpar(e2); 3336 elem *ep = el_params(e2, e1, getTypeInfo(ce.e1.loc, ce.e1.type, irs), null); 3337 e = el_bin(OPcall, TYdarray, el_var(getRtlsym(RTLSYM_ARRAYAPPENDT)), ep); 3338 toTraceGC(irs, e, ce.loc); 3339 break; 3340 } 3341 3342 case TOK.concatenateElemAssign: 3343 { 3344 // Append element 3345 assert(tb1n.equals(tb2)); 3346 3347 elem *e2x = null; 3348 3349 if (e2.Eoper != OPvar && e2.Eoper != OPconst) 3350 { 3351 // Evaluate e2 and assign result to temporary s2. 3352 // Do this because of: 3353 // a ~= a[$-1] 3354 // because $ changes its value 3355 type* tx = Type_toCtype(tb2); 3356 Symbol *s2 = symbol_genauto(tx); 3357 e2x = elAssign(el_var(s2), e2, tb1n, tx); 3358 3359 e2 = el_var(s2); 3360 } 3361 3362 // Extend array with _d_arrayappendcTX(TypeInfo ti, e1, 1) 3363 e1 = el_una(OPaddr, TYnptr, e1); 3364 elem *ep = el_param(e1, getTypeInfo(ce.e1.loc, ce.e1.type, irs)); 3365 ep = el_param(el_long(TYsize_t, 1), ep); 3366 e = el_bin(OPcall, TYdarray, el_var(getRtlsym(RTLSYM_ARRAYAPPENDCTX)), ep); 3367 toTraceGC(irs, e, ce.loc); 3368 Symbol *stmp = symbol_genauto(Type_toCtype(tb1)); 3369 e = el_bin(OPeq, TYdarray, el_var(stmp), e); 3370 3371 // Assign e2 to last element in stmp[] 3372 // *(stmp.ptr + (stmp.length - 1) * szelem) = e2 3373 3374 elem *eptr = array_toPtr(tb1, el_var(stmp)); 3375 elem *elength = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, el_var(stmp)); 3376 elength = el_bin(OPmin, TYsize_t, elength, el_long(TYsize_t, 1)); 3377 elength = el_bin(OPmul, TYsize_t, elength, el_long(TYsize_t, ce.e2.type.size())); 3378 eptr = el_bin(OPadd, TYnptr, eptr, elength); 3379 elem *ederef = el_una(OPind, e2.Ety, eptr); 3380 3381 elem *eeq = elAssign(ederef, e2, tb1n, null); 3382 e = el_combine(e2x, e); 3383 e = el_combine(e, eeq); 3384 e = el_combine(e, el_var(stmp)); 3385 break; 3386 } 3387 3388 default: 3389 assert(0); 3390 } 3391 elem_setLoc(e, ce.loc); 3392 result = e; 3393 } 3394 3395 /*************************************** 3396 */ 3397 3398 override void visit(DivAssignExp e) 3399 { 3400 result = toElemBinAssign(e, OPdivass); 3401 } 3402 3403 /*************************************** 3404 */ 3405 3406 override void visit(ModAssignExp e) 3407 { 3408 result = toElemBinAssign(e, OPmodass); 3409 } 3410 3411 /*************************************** 3412 */ 3413 3414 override void visit(MulAssignExp e) 3415 { 3416 result = toElemBinAssign(e, OPmulass); 3417 } 3418 3419 /*************************************** 3420 */ 3421 3422 override void visit(ShlAssignExp e) 3423 { 3424 result = toElemBinAssign(e, OPshlass); 3425 } 3426 3427 /*************************************** 3428 */ 3429 3430 override void visit(ShrAssignExp e) 3431 { 3432 //printf("ShrAssignExp.toElem() %s, %s\n", e.e1.type.toChars(), e.e1.toChars()); 3433 Type t1 = e.e1.type; 3434 if (e.e1.op == TOK.cast_) 3435 { 3436 /* Use the type before it was integrally promoted to int 3437 */ 3438 CastExp ce = cast(CastExp)e.e1; 3439 t1 = ce.e1.type; 3440 } 3441 result = toElemBinAssign(e, t1.isunsigned() ? OPshrass : OPashrass); 3442 } 3443 3444 /*************************************** 3445 */ 3446 3447 override void visit(UshrAssignExp e) 3448 { 3449 result = toElemBinAssign(e, OPshrass); 3450 } 3451 3452 /*************************************** 3453 */ 3454 3455 override void visit(AndAssignExp e) 3456 { 3457 result = toElemBinAssign(e, OPandass); 3458 } 3459 3460 /*************************************** 3461 */ 3462 3463 override void visit(OrAssignExp e) 3464 { 3465 result = toElemBinAssign(e, OPorass); 3466 } 3467 3468 /*************************************** 3469 */ 3470 3471 override void visit(XorAssignExp e) 3472 { 3473 result = toElemBinAssign(e, OPxorass); 3474 } 3475 3476 /*************************************** 3477 */ 3478 3479 override void visit(LogicalExp aae) 3480 { 3481 tym_t tym = totym(aae.type); 3482 3483 elem *el = toElem(aae.e1, irs); 3484 elem *er = toElemDtor(aae.e2, irs); 3485 elem *e = el_bin(aae.op == TOK.andAnd ? OPandand : OPoror,tym,el,er); 3486 3487 elem_setLoc(e, aae.loc); 3488 3489 if (irs.params.cov && aae.e2.loc.linnum) 3490 e.EV.E2 = el_combine(incUsageElem(irs, aae.e2.loc), e.EV.E2); 3491 result = e; 3492 } 3493 3494 /*************************************** 3495 */ 3496 3497 override void visit(XorExp e) 3498 { 3499 result = toElemBin(e, OPxor); 3500 } 3501 3502 /*************************************** 3503 */ 3504 3505 override void visit(AndExp e) 3506 { 3507 result = toElemBin(e, OPand); 3508 } 3509 3510 /*************************************** 3511 */ 3512 3513 override void visit(OrExp e) 3514 { 3515 result = toElemBin(e, OPor); 3516 } 3517 3518 /*************************************** 3519 */ 3520 3521 override void visit(ShlExp e) 3522 { 3523 result = toElemBin(e, OPshl); 3524 } 3525 3526 /*************************************** 3527 */ 3528 3529 override void visit(ShrExp e) 3530 { 3531 result = toElemBin(e, e.e1.type.isunsigned() ? OPshr : OPashr); 3532 } 3533 3534 /*************************************** 3535 */ 3536 3537 override void visit(UshrExp se) 3538 { 3539 elem *eleft = toElem(se.e1, irs); 3540 eleft.Ety = touns(eleft.Ety); 3541 elem *eright = toElem(se.e2, irs); 3542 elem *e = el_bin(OPshr, totym(se.type), eleft, eright); 3543 elem_setLoc(e, se.loc); 3544 result = e; 3545 } 3546 3547 /**************************************** 3548 */ 3549 3550 override void visit(CommaExp ce) 3551 { 3552 assert(ce.e1 && ce.e2); 3553 elem *eleft = toElem(ce.e1, irs); 3554 elem *eright = toElem(ce.e2, irs); 3555 elem *e = el_combine(eleft, eright); 3556 if (e) 3557 elem_setLoc(e, ce.loc); 3558 result = e; 3559 } 3560 3561 /*************************************** 3562 */ 3563 3564 override void visit(CondExp ce) 3565 { 3566 elem *ec = toElem(ce.econd, irs); 3567 3568 elem *eleft = toElem(ce.e1, irs); 3569 if (irs.params.cov && ce.e1.loc.linnum) 3570 eleft = el_combine(incUsageElem(irs, ce.e1.loc), eleft); 3571 3572 elem *eright = toElem(ce.e2, irs); 3573 if (irs.params.cov && ce.e2.loc.linnum) 3574 eright = el_combine(incUsageElem(irs, ce.e2.loc), eright); 3575 3576 tym_t ty = eleft.Ety; 3577 if (ce.e1.type.toBasetype().ty == Tvoid || 3578 ce.e2.type.toBasetype().ty == Tvoid) 3579 ty = TYvoid; 3580 3581 elem *e = el_bin(OPcond, ty, ec, el_bin(OPcolon, ty, eleft, eright)); 3582 if (tybasic(ty) == TYstruct) 3583 e.ET = Type_toCtype(ce.e1.type); 3584 elem_setLoc(e, ce.loc); 3585 result = e; 3586 } 3587 3588 /*************************************** 3589 */ 3590 3591 override void visit(TypeExp e) 3592 { 3593 //printf("TypeExp.toElem()\n"); 3594 e.error("type `%s` is not an expression", e.toChars()); 3595 result = el_long(TYint, 0); 3596 } 3597 3598 override void visit(ScopeExp e) 3599 { 3600 e.error("`%s` is not an expression", e.sds.toChars()); 3601 result = el_long(TYint, 0); 3602 } 3603 3604 override void visit(DotVarExp dve) 3605 { 3606 // *(&e + offset) 3607 3608 //printf("[%s] DotVarExp.toElem('%s')\n", dve.loc.toChars(), dve.toChars()); 3609 3610 VarDeclaration v = dve.var.isVarDeclaration(); 3611 if (!v) 3612 { 3613 dve.error("`%s` is not a field, but a %s", dve.var.toChars(), dve.var.kind()); 3614 result = el_long(TYint, 0); 3615 return; 3616 } 3617 3618 // https://issues.dlang.org/show_bug.cgi?id=12900 3619 Type txb = dve.type.toBasetype(); 3620 Type tyb = v.type.toBasetype(); 3621 if (auto tv = txb.isTypeVector()) txb = tv.basetype; 3622 if (auto tv = tyb.isTypeVector()) tyb = tv.basetype; 3623 3624 debug if (txb.ty != tyb.ty) 3625 printf("[%s] dve = %s, dve.type = %s, v.type = %s\n", dve.loc.toChars(), dve.toChars(), dve.type.toChars(), v.type.toChars()); 3626 3627 assert(txb.ty == tyb.ty); 3628 3629 // https://issues.dlang.org/show_bug.cgi?id=14730 3630 if (irs.params.useInline && v.offset == 0) 3631 { 3632 FuncDeclaration fd = v.parent.isFuncDeclaration(); 3633 if (fd && fd.semanticRun < PASS.obj) 3634 setClosureVarOffset(fd); 3635 } 3636 3637 elem *e = toElem(dve.e1, irs); 3638 Type tb1 = dve.e1.type.toBasetype(); 3639 tym_t typ = TYnptr; 3640 if (tb1.ty != Tclass && tb1.ty != Tpointer) 3641 { 3642 e = addressElem(e, tb1); 3643 typ = tybasic(e.Ety); 3644 } 3645 auto offset = el_long(TYsize_t, v.offset); 3646 offset = objc.getOffset(v, tb1, offset); 3647 e = el_bin(OPadd, typ, e, offset); 3648 if (v.storage_class & (STC.out_ | STC.ref_)) 3649 e = el_una(OPind, TYnptr, e); 3650 e = el_una(OPind, totym(dve.type), e); 3651 if (tybasic(e.Ety) == TYstruct) 3652 { 3653 e.ET = Type_toCtype(dve.type); 3654 } 3655 elem_setLoc(e,dve.loc); 3656 result = e; 3657 } 3658 3659 override void visit(DelegateExp de) 3660 { 3661 int directcall = 0; 3662 //printf("DelegateExp.toElem() '%s'\n", de.toChars()); 3663 3664 if (de.func.semanticRun == PASS.semantic3done) 3665 { 3666 // Bug 7745 - only include the function if it belongs to this module 3667 // ie, it is a member of this module, or is a template instance 3668 // (the template declaration could come from any module). 3669 Dsymbol owner = de.func.toParent(); 3670 while (!owner.isTemplateInstance() && owner.toParent()) 3671 owner = owner.toParent(); 3672 if (owner.isTemplateInstance() || owner == irs.m ) 3673 { 3674 irs.deferToObj.push(de.func); 3675 } 3676 } 3677 3678 elem *eeq = null; 3679 elem *ethis; 3680 Symbol *sfunc = toSymbol(de.func); 3681 elem *ep; 3682 3683 elem *ethis2 = null; 3684 if (de.vthis2) 3685 { 3686 // avoid using toSymbol directly because vthis2 may be a closure var 3687 Expression ve = new VarExp(de.loc, de.vthis2); 3688 ve.type = de.vthis2.type; 3689 ve = new AddrExp(de.loc, ve); 3690 ve.type = de.vthis2.type.pointerTo(); 3691 ethis2 = toElem(ve, irs); 3692 } 3693 3694 if (de.func.isNested() && !de.func.isThis()) 3695 { 3696 ep = el_ptr(sfunc); 3697 if (de.e1.op == TOK.null_) 3698 ethis = toElem(de.e1, irs); 3699 else 3700 ethis = getEthis(de.loc, irs, de.func, de.func.toParentLocal()); 3701 3702 if (ethis2) 3703 ethis2 = setEthis2(de.loc, irs, de.func, ethis2, ðis, &eeq); 3704 } 3705 else 3706 { 3707 ethis = toElem(de.e1, irs); 3708 if (de.e1.type.ty != Tclass && de.e1.type.ty != Tpointer) 3709 ethis = addressElem(ethis, de.e1.type); 3710 3711 if (ethis2) 3712 ethis2 = setEthis2(de.loc, irs, de.func, ethis2, ðis, &eeq); 3713 3714 if (de.e1.op == TOK.super_ || de.e1.op == TOK.dotType) 3715 directcall = 1; 3716 3717 if (!de.func.isThis()) 3718 de.error("delegates are only for non-static functions"); 3719 3720 if (!de.func.isVirtual() || 3721 directcall || 3722 de.func.isFinalFunc()) 3723 { 3724 ep = el_ptr(sfunc); 3725 } 3726 else 3727 { 3728 // Get pointer to function out of virtual table 3729 3730 assert(ethis); 3731 ep = el_same(ðis); 3732 ep = el_una(OPind, TYnptr, ep); 3733 uint vindex = de.func.vtblIndex; 3734 3735 assert(cast(int)vindex >= 0); 3736 3737 // Build *(ep + vindex * 4) 3738 ep = el_bin(OPadd,TYnptr,ep,el_long(TYsize_t, vindex * target.ptrsize)); 3739 ep = el_una(OPind,TYnptr,ep); 3740 } 3741 3742 //if (func.tintro) 3743 // func.error(loc, "cannot form delegate due to covariant return type"); 3744 } 3745 3746 elem *e; 3747 if (ethis2) 3748 ethis = ethis2; 3749 if (ethis.Eoper == OPcomma) 3750 { 3751 ethis.EV.E2 = el_pair(TYdelegate, ethis.EV.E2, ep); 3752 ethis.Ety = TYdelegate; 3753 e = ethis; 3754 } 3755 else 3756 e = el_pair(TYdelegate, ethis, ep); 3757 elem_setLoc(e, de.loc); 3758 if (eeq) 3759 e = el_combine(eeq, e); 3760 result = e; 3761 } 3762 3763 override void visit(DotTypeExp dte) 3764 { 3765 // Just a pass-thru to e1 3766 //printf("DotTypeExp.toElem() %s\n", dte.toChars()); 3767 elem *e = toElem(dte.e1, irs); 3768 elem_setLoc(e, dte.loc); 3769 result = e; 3770 } 3771 3772 override void visit(CallExp ce) 3773 { 3774 //printf("[%s] CallExp.toElem('%s') %p, %s\n", ce.loc.toChars(), ce.toChars(), ce, ce.type.toChars()); 3775 assert(ce.e1.type); 3776 Type t1 = ce.e1.type.toBasetype(); 3777 Type ectype = t1; 3778 elem *eeq = null; 3779 3780 elem *ehidden = irs.ehidden; 3781 irs.ehidden = null; 3782 3783 elem *ec; 3784 FuncDeclaration fd = null; 3785 bool dctor = false; 3786 if (ce.e1.op == TOK.dotVariable && t1.ty != Tdelegate) 3787 { 3788 DotVarExp dve = cast(DotVarExp)ce.e1; 3789 3790 fd = dve.var.isFuncDeclaration(); 3791 3792 if (auto sle = dve.e1.isStructLiteralExp()) 3793 { 3794 if (fd && fd.isCtorDeclaration() || 3795 fd.type.isMutable() || 3796 sle.type.size() <= 8) // more efficient than fPIC 3797 sle.useStaticInit = false; // don't modify initializer, so make copy 3798 } 3799 3800 ec = toElem(dve.e1, irs); 3801 ectype = dve.e1.type.toBasetype(); 3802 3803 /* Recognize: 3804 * [1] ce: ((S __ctmp = initializer),__ctmp).ctor(args) 3805 * where the left of the . was turned into [2] or [3] for EH_DWARF: 3806 * [2] ec: (dctor info ((__ctmp = initializer),__ctmp)), __ctmp 3807 * [3] ec: (dctor info ((_flag=0),((__ctmp = initializer),__ctmp))), __ctmp 3808 * The trouble 3809 * https://issues.dlang.org/show_bug.cgi?id=13095 3810 * is if ctor(args) throws, then __ctmp is destructed even though __ctmp 3811 * is not a fully constructed object yet. The solution is to move the ctor(args) itno the dctor tree. 3812 * But first, detect [1], then [2], then split up [2] into: 3813 * eeq: (dctor info ((__ctmp = initializer),__ctmp)) 3814 * eeq: (dctor info ((_flag=0),((__ctmp = initializer),__ctmp))) for EH_DWARF 3815 * ec: __ctmp 3816 */ 3817 if (fd && fd.isCtorDeclaration()) 3818 { 3819 //printf("test30 %s\n", dve.e1.toChars()); 3820 if (dve.e1.op == TOK.comma) 3821 { 3822 //printf("test30a\n"); 3823 if ((cast(CommaExp)dve.e1).e1.op == TOK.declaration && (cast(CommaExp)dve.e1).e2.op == TOK.variable) 3824 { // dve.e1: (declaration , var) 3825 3826 //printf("test30b\n"); 3827 if (ec.Eoper == OPcomma && 3828 ec.EV.E1.Eoper == OPinfo && 3829 ec.EV.E1.EV.E1.Eoper == OPdctor && 3830 ec.EV.E1.EV.E2.Eoper == OPcomma) 3831 { // ec: ((dctor info (* , *)) , *) 3832 3833 //printf("test30c\n"); 3834 dctor = true; // remember we detected it 3835 3836 // Split ec into eeq and ec per comment above 3837 eeq = ec.EV.E1; // (dctor info (*, *)) 3838 ec.EV.E1 = null; 3839 ec = el_selecte2(ec); // * 3840 } 3841 } 3842 } 3843 } 3844 3845 3846 if (dctor) 3847 { 3848 } 3849 else if (ce.arguments && ce.arguments.dim && ec.Eoper != OPvar) 3850 { 3851 if (ec.Eoper == OPind && el_sideeffect(ec.EV.E1)) 3852 { 3853 /* Rewrite (*exp)(arguments) as: 3854 * tmp = exp, (*tmp)(arguments) 3855 */ 3856 elem *ec1 = ec.EV.E1; 3857 Symbol *stmp = symbol_genauto(type_fake(ec1.Ety)); 3858 eeq = el_bin(OPeq, ec.Ety, el_var(stmp), ec1); 3859 ec.EV.E1 = el_var(stmp); 3860 } 3861 else if (tybasic(ec.Ety) != TYnptr) 3862 { 3863 /* Rewrite (exp)(arguments) as: 3864 * tmp=&exp, (*tmp)(arguments) 3865 */ 3866 ec = addressElem(ec, ectype); 3867 3868 Symbol *stmp = symbol_genauto(type_fake(ec.Ety)); 3869 eeq = el_bin(OPeq, ec.Ety, el_var(stmp), ec); 3870 ec = el_una(OPind, totym(ectype), el_var(stmp)); 3871 } 3872 } 3873 } 3874 else if (ce.e1.op == TOK.variable) 3875 { 3876 fd = (cast(VarExp)ce.e1).var.isFuncDeclaration(); 3877 version (none) 3878 { 3879 // This optimization is not valid if alloca can be called 3880 // multiple times within the same function, eg in a loop 3881 // see issue 3822 3882 if (fd && fd.ident == Id.__alloca && 3883 !fd.fbody && fd.linkage == LINK.c && 3884 arguments && arguments.dim == 1) 3885 { Expression arg = (*arguments)[0]; 3886 arg = arg.optimize(WANTvalue); 3887 if (arg.isConst() && arg.type.isintegral()) 3888 { dinteger_t sz = arg.toInteger(); 3889 if (sz > 0 && sz < 0x40000) 3890 { 3891 // It's an alloca(sz) of a fixed amount. 3892 // Replace with an array allocated on the stack 3893 // of the same size: char[sz] tmp; 3894 3895 assert(!ehidden); 3896 .type *t = type_static_array(sz, tschar); // BUG: fix extra Tcount++ 3897 Symbol *stmp = symbol_genauto(t); 3898 ec = el_ptr(stmp); 3899 elem_setLoc(ec,loc); 3900 return ec; 3901 } 3902 } 3903 } 3904 } 3905 3906 ec = toElem(ce.e1, irs); 3907 } 3908 else 3909 { 3910 ec = toElem(ce.e1, irs); 3911 if (ce.arguments && ce.arguments.dim) 3912 { 3913 /* The idea is to enforce expressions being evaluated left to right, 3914 * even though call trees are evaluated parameters first. 3915 * We just do a quick hack to catch the more obvious cases, though 3916 * we need to solve this generally. 3917 */ 3918 if (ec.Eoper == OPind && el_sideeffect(ec.EV.E1)) 3919 { 3920 /* Rewrite (*exp)(arguments) as: 3921 * tmp=exp, (*tmp)(arguments) 3922 */ 3923 elem *ec1 = ec.EV.E1; 3924 Symbol *stmp = symbol_genauto(type_fake(ec1.Ety)); 3925 eeq = el_bin(OPeq, ec.Ety, el_var(stmp), ec1); 3926 ec.EV.E1 = el_var(stmp); 3927 } 3928 else if (tybasic(ec.Ety) == TYdelegate && el_sideeffect(ec)) 3929 { 3930 /* Rewrite (exp)(arguments) as: 3931 * tmp=exp, (tmp)(arguments) 3932 */ 3933 Symbol *stmp = symbol_genauto(type_fake(ec.Ety)); 3934 eeq = el_bin(OPeq, ec.Ety, el_var(stmp), ec); 3935 ec = el_var(stmp); 3936 } 3937 } 3938 } 3939 elem *ethis2 = null; 3940 if (ce.vthis2) 3941 { 3942 // avoid using toSymbol directly because vthis2 may be a closure var 3943 Expression ve = new VarExp(ce.loc, ce.vthis2); 3944 ve.type = ce.vthis2.type; 3945 ve = new AddrExp(ce.loc, ve); 3946 ve.type = ce.vthis2.type.pointerTo(); 3947 ethis2 = toElem(ve, irs); 3948 } 3949 elem *ecall = callfunc(ce.loc, irs, ce.directcall, ce.type, ec, ectype, fd, t1, ehidden, ce.arguments, null, ethis2); 3950 3951 if (dctor && ecall.Eoper == OPind) 3952 { 3953 /* Continuation of fix outlined above for moving constructor call into dctor tree. 3954 * Given: 3955 * eeq: (dctor info ((__ctmp = initializer),__ctmp)) 3956 * eeq: (dctor info ((_flag=0),((__ctmp = initializer),__ctmp))) for EH_DWARF 3957 * ecall: * call(ce, args) 3958 * Rewrite ecall as: 3959 * * (dctor info ((__ctmp = initializer),call(ce, args))) 3960 * * (dctor info ((_flag=0),(__ctmp = initializer),call(ce, args))) 3961 */ 3962 elem *ea = ecall.EV.E1; // ea: call(ce,args) 3963 tym_t ty = ea.Ety; 3964 ecall.EV.E1 = eeq; 3965 assert(eeq.Eoper == OPinfo); 3966 elem *eeqcomma = eeq.EV.E2; 3967 assert(eeqcomma.Eoper == OPcomma); 3968 while (eeqcomma.EV.E2.Eoper == OPcomma) 3969 { 3970 eeqcomma.Ety = ty; 3971 eeqcomma = eeqcomma.EV.E2; 3972 } 3973 eeq.Ety = ty; 3974 el_free(eeqcomma.EV.E2); 3975 eeqcomma.EV.E2 = ea; // replace ,__ctmp with ,call(ce,args) 3976 eeqcomma.Ety = ty; 3977 eeq = null; 3978 } 3979 3980 elem_setLoc(ecall, ce.loc); 3981 if (eeq) 3982 ecall = el_combine(eeq, ecall); 3983 result = ecall; 3984 } 3985 3986 override void visit(AddrExp ae) 3987 { 3988 //printf("AddrExp.toElem('%s')\n", ae.toChars()); 3989 if (auto sle = ae.e1.isStructLiteralExp()) 3990 { 3991 //printf("AddrExp.toElem('%s') %d\n", ae.toChars(), ae); 3992 //printf("StructLiteralExp(%p); origin:%p\n", sle, sle.origin); 3993 //printf("sle.toSymbol() (%p)\n", sle.toSymbol()); 3994 elem *e = el_ptr(toSymbol(sle.origin)); 3995 e.ET = Type_toCtype(ae.type); 3996 elem_setLoc(e, ae.loc); 3997 result = e; 3998 return; 3999 } 4000 else 4001 { 4002 elem *e = toElem(ae.e1, irs); 4003 e = addressElem(e, ae.e1.type); 4004 e.Ety = totym(ae.type); 4005 elem_setLoc(e, ae.loc); 4006 result = e; 4007 return; 4008 } 4009 } 4010 4011 override void visit(PtrExp pe) 4012 { 4013 //printf("PtrExp.toElem() %s\n", pe.toChars()); 4014 elem *e = toElem(pe.e1, irs); 4015 if (tybasic(e.Ety) == TYnptr && 4016 pe.e1.type.nextOf() && 4017 pe.e1.type.nextOf().isImmutable()) 4018 { 4019 e.Ety = TYimmutPtr; // pointer to immutable 4020 } 4021 e = el_una(OPind,totym(pe.type),e); 4022 if (tybasic(e.Ety) == TYstruct) 4023 { 4024 e.ET = Type_toCtype(pe.type); 4025 } 4026 elem_setLoc(e, pe.loc); 4027 result = e; 4028 } 4029 4030 override void visit(DeleteExp de) 4031 { 4032 Type tb; 4033 4034 //printf("DeleteExp.toElem()\n"); 4035 if (de.e1.op == TOK.index) 4036 { 4037 IndexExp ae = cast(IndexExp)de.e1; 4038 tb = ae.e1.type.toBasetype(); 4039 assert(tb.ty != Taarray); 4040 } 4041 //e1.type.print(); 4042 elem *e = toElem(de.e1, irs); 4043 tb = de.e1.type.toBasetype(); 4044 int rtl; 4045 switch (tb.ty) 4046 { 4047 case Tarray: 4048 { 4049 e = addressElem(e, de.e1.type); 4050 rtl = RTLSYM_DELARRAYT; 4051 4052 /* See if we need to run destructors on the array contents 4053 */ 4054 elem *et = null; 4055 Type tv = tb.nextOf().baseElemOf(); 4056 if (auto ts = tv.isTypeStruct()) 4057 { 4058 // FIXME: ts can be non-mutable, but _d_delarray_t requests TypeInfo_Struct. 4059 StructDeclaration sd = ts.sym; 4060 if (sd.dtor) 4061 et = getTypeInfo(de.e1.loc, tb.nextOf(), irs); 4062 } 4063 if (!et) // if no destructors needed 4064 et = el_long(TYnptr, 0); // pass null for TypeInfo 4065 e = el_params(et, e, null); 4066 // call _d_delarray_t(e, et); 4067 break; 4068 } 4069 case Tclass: 4070 if (de.e1.op == TOK.variable) 4071 { 4072 VarExp ve = cast(VarExp)de.e1; 4073 if (ve.var.isVarDeclaration() && 4074 ve.var.isVarDeclaration().onstack) 4075 { 4076 rtl = RTLSYM_CALLFINALIZER; 4077 if (tb.isClassHandle().isInterfaceDeclaration()) 4078 rtl = RTLSYM_CALLINTERFACEFINALIZER; 4079 break; 4080 } 4081 } 4082 e = addressElem(e, de.e1.type); 4083 rtl = RTLSYM_DELCLASS; 4084 if (tb.isClassHandle().isInterfaceDeclaration()) 4085 rtl = RTLSYM_DELINTERFACE; 4086 break; 4087 4088 case Tpointer: 4089 e = addressElem(e, de.e1.type); 4090 rtl = RTLSYM_DELMEMORY; 4091 tb = (cast(TypePointer)tb).next.toBasetype(); 4092 if (auto ts = tb.isTypeStruct()) 4093 { 4094 if (ts.sym.dtor) 4095 { 4096 rtl = RTLSYM_DELSTRUCT; 4097 elem *et = getTypeInfo(de.e1.loc, tb, irs); 4098 e = el_params(et, e, null); 4099 } 4100 } 4101 break; 4102 4103 default: 4104 assert(0); 4105 } 4106 e = el_bin(OPcall, TYvoid, el_var(getRtlsym(rtl)), e); 4107 toTraceGC(irs, e, de.loc); 4108 elem_setLoc(e, de.loc); 4109 result = e; 4110 } 4111 4112 override void visit(VectorExp ve) 4113 { 4114 version (none) 4115 { 4116 printf("VectorExp.toElem()\n"); 4117 ve.print(); 4118 printf("\tfrom: %s\n", ve.e1.type.toChars()); 4119 printf("\tto : %s\n", ve.to.toChars()); 4120 } 4121 4122 elem* e; 4123 if (ve.e1.op == TOK.arrayLiteral) 4124 { 4125 e = el_calloc(); 4126 e.Eoper = OPconst; 4127 e.Ety = totym(ve.type); 4128 4129 foreach (const i; 0 .. ve.dim) 4130 { 4131 Expression elem = ve.e1.isArrayLiteralExp()[i]; 4132 const complex = elem.toComplex(); 4133 const integer = elem.toInteger(); 4134 switch (elem.type.toBasetype().ty) 4135 { 4136 case Tfloat32: 4137 // Must not call toReal directly, to avoid dmd bug 14203 from breaking dmd 4138 e.EV.Vfloat8[i] = cast(float) complex.re; 4139 break; 4140 4141 case Tfloat64: 4142 // Must not call toReal directly, to avoid dmd bug 14203 from breaking dmd 4143 e.EV.Vdouble4[i] = cast(double) complex.re; 4144 break; 4145 4146 case Tint64: 4147 case Tuns64: 4148 e.EV.Vullong4[i] = integer; 4149 break; 4150 4151 case Tint32: 4152 case Tuns32: 4153 e.EV.Vulong8[i] = cast(uint)integer; 4154 break; 4155 4156 case Tint16: 4157 case Tuns16: 4158 e.EV.Vushort16[i] = cast(ushort)integer; 4159 break; 4160 4161 case Tint8: 4162 case Tuns8: 4163 e.EV.Vuchar32[i] = cast(ubyte)integer; 4164 break; 4165 4166 default: 4167 assert(0); 4168 } 4169 } 4170 } 4171 else 4172 { 4173 // Create vecfill(e1) 4174 elem* e1 = toElem(ve.e1, irs); 4175 e = el_una(OPvecfill, totym(ve.type), e1); 4176 } 4177 elem_setLoc(e, ve.loc); 4178 result = e; 4179 } 4180 4181 override void visit(VectorArrayExp vae) 4182 { 4183 // Generate code for `vec.array` 4184 if (auto ve = vae.e1.isVectorExp()) 4185 { 4186 // https://issues.dlang.org/show_bug.cgi?id=19607 4187 // When viewing a vector literal as an array, build the underlying array directly. 4188 if (ve.e1.op == TOK.arrayLiteral) 4189 result = toElem(ve.e1, irs); 4190 else 4191 { 4192 // Generate: stmp[0 .. dim] = e1 4193 type* tarray = Type_toCtype(vae.type); 4194 Symbol* stmp = symbol_genauto(tarray); 4195 result = setArray(ve.e1, el_ptr(stmp), el_long(TYsize_t, tarray.Tdim), 4196 ve.e1.type, toElem(ve.e1, irs), irs, TOK.blit); 4197 result = el_combine(result, el_var(stmp)); 4198 result.ET = tarray; 4199 } 4200 } 4201 else 4202 { 4203 // For other vector expressions this just a paint operation. 4204 elem* e = toElem(vae.e1, irs); 4205 type* tarray = Type_toCtype(vae.type); 4206 // Take the address then repaint, 4207 // this makes it swap to the right registers 4208 e = addressElem(e, vae.e1.type); 4209 e = el_una(OPind, tarray.Tty, e); 4210 e.ET = tarray; 4211 result = e; 4212 } 4213 result.Ety = totym(vae.type); 4214 elem_setLoc(result, vae.loc); 4215 } 4216 4217 override void visit(CastExp ce) 4218 { 4219 version (none) 4220 { 4221 printf("CastExp.toElem()\n"); 4222 ce.print(); 4223 printf("\tfrom: %s\n", ce.e1.type.toChars()); 4224 printf("\tto : %s\n", ce.to.toChars()); 4225 } 4226 elem *e = toElem(ce.e1, irs); 4227 4228 result = toElemCast(ce, e, false); 4229 } 4230 4231 elem *toElemCast(CastExp ce, elem *e, bool isLvalue) 4232 { 4233 tym_t ftym; 4234 tym_t ttym; 4235 OPER eop; 4236 4237 Type tfrom = ce.e1.type.toBasetype(); 4238 Type t = ce.to.toBasetype(); // skip over typedef's 4239 4240 TY fty; 4241 TY tty; 4242 if (t.equals(tfrom) || 4243 t.equals(Type.tvoid)) // https://issues.dlang.org/show_bug.cgi?id=18573 4244 // Remember to pop value left on FPU stack 4245 return e; 4246 4247 fty = tfrom.ty; 4248 tty = t.ty; 4249 //printf("fty = %d\n", fty); 4250 4251 static elem* Lret(CastExp ce, elem* e) 4252 { 4253 // Adjust for any type paints 4254 Type t = ce.type.toBasetype(); 4255 e.Ety = totym(t); 4256 if (tyaggregate(e.Ety)) 4257 e.ET = Type_toCtype(t); 4258 4259 elem_setLoc(e, ce.loc); 4260 return e; 4261 } 4262 4263 static elem* Lpaint(CastExp ce, elem* e, tym_t ttym) 4264 { 4265 e.Ety = ttym; 4266 return Lret(ce, e); 4267 } 4268 4269 static elem* Lzero(CastExp ce, elem* e, tym_t ttym) 4270 { 4271 e = el_bin(OPcomma, ttym, e, el_long(ttym, 0)); 4272 return Lret(ce, e); 4273 } 4274 4275 static elem* Leop(CastExp ce, elem* e, OPER eop, tym_t ttym) 4276 { 4277 e = el_una(eop, ttym, e); 4278 return Lret(ce, e); 4279 } 4280 4281 if (tty == Tpointer && fty == Tarray) 4282 { 4283 if (e.Eoper == OPvar) 4284 { 4285 // e1 . *(&e1 + 4) 4286 e = el_una(OPaddr, TYnptr, e); 4287 e = el_bin(OPadd, TYnptr, e, el_long(TYsize_t, tysize(TYnptr))); 4288 e = el_una(OPind,totym(t),e); 4289 } 4290 else 4291 { 4292 // e1 . (uint)(e1 >> 32) 4293 if (irs.params.is64bit) 4294 { 4295 e = el_bin(OPshr, TYucent, e, el_long(TYint, 64)); 4296 e = el_una(OP128_64, totym(t), e); 4297 } 4298 else 4299 { 4300 e = el_bin(OPshr, TYullong, e, el_long(TYint, 32)); 4301 e = el_una(OP64_32, totym(t), e); 4302 } 4303 } 4304 return Lret(ce, e); 4305 } 4306 4307 if (tty == Tpointer && fty == Tsarray) 4308 { 4309 // e1 . &e1 4310 e = el_una(OPaddr, TYnptr, e); 4311 return Lret(ce, e); 4312 } 4313 4314 // Convert from static array to dynamic array 4315 if (tty == Tarray && fty == Tsarray) 4316 { 4317 e = sarray_toDarray(ce.loc, tfrom, t, e); 4318 return Lret(ce, e); 4319 } 4320 4321 // Convert from dynamic array to dynamic array 4322 if (tty == Tarray && fty == Tarray) 4323 { 4324 uint fsize = cast(uint)tfrom.nextOf().size(); 4325 uint tsize = cast(uint)t.nextOf().size(); 4326 4327 if (fsize != tsize) 4328 { // Array element sizes do not match, so we must adjust the dimensions 4329 if (tsize != 0 && fsize % tsize == 0) 4330 { 4331 // Set array dimension to (length * (fsize / tsize)) 4332 // Generate pair(e.length * (fsize/tsize), es.ptr) 4333 4334 elem *es = el_same(&e); 4335 4336 elem *eptr = el_una(OPmsw, TYnptr, es); 4337 elem *elen = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, e); 4338 elem *elen2 = el_bin(OPmul, TYsize_t, elen, el_long(TYsize_t, fsize / tsize)); 4339 e = el_pair(totym(ce.type), elen2, eptr); 4340 } 4341 else 4342 { 4343 assert(false, "This case should have been rewritten to `__ArrayCast` in the semantic phase"); 4344 } 4345 } 4346 return Lret(ce, e); 4347 } 4348 4349 // Casting between class/interface may require a runtime check 4350 if (fty == Tclass && tty == Tclass) 4351 { 4352 ClassDeclaration cdfrom = tfrom.isClassHandle(); 4353 ClassDeclaration cdto = t.isClassHandle(); 4354 4355 int offset; 4356 if (cdto.isBaseOf(cdfrom, &offset) && offset != ClassDeclaration.OFFSET_RUNTIME) 4357 { 4358 /* The offset from cdfrom => cdto is known at compile time. 4359 * Cases: 4360 * - class => base class (upcast) 4361 * - class => base interface (upcast) 4362 */ 4363 4364 //printf("offset = %d\n", offset); 4365 if (offset == ClassDeclaration.OFFSET_FWDREF) 4366 { 4367 assert(0, "unexpected forward reference"); 4368 } 4369 else if (offset) 4370 { 4371 /* Rewrite cast as (e ? e + offset : null) 4372 */ 4373 if (ce.e1.op == TOK.this_) 4374 { 4375 // Assume 'this' is never null, so skip null check 4376 e = el_bin(OPadd, TYnptr, e, el_long(TYsize_t, offset)); 4377 } 4378 else 4379 { 4380 elem *etmp = el_same(&e); 4381 elem *ex = el_bin(OPadd, TYnptr, etmp, el_long(TYsize_t, offset)); 4382 ex = el_bin(OPcolon, TYnptr, ex, el_long(TYnptr, 0)); 4383 e = el_bin(OPcond, TYnptr, e, ex); 4384 } 4385 } 4386 else 4387 { 4388 // Casting from derived class to base class is a no-op 4389 } 4390 } 4391 else if (cdfrom.classKind == ClassKind.cpp) 4392 { 4393 if (cdto.classKind == ClassKind.cpp) 4394 { 4395 /* Casting from a C++ interface to a C++ interface 4396 * is always a 'paint' operation 4397 */ 4398 return Lret(ce, e); // no-op 4399 } 4400 4401 /* Casting from a C++ interface to a class 4402 * always results in null because there is no runtime 4403 * information available to do it. 4404 * 4405 * Casting from a C++ interface to a non-C++ interface 4406 * always results in null because there's no way one 4407 * can be derived from the other. 4408 */ 4409 e = el_bin(OPcomma, TYnptr, e, el_long(TYnptr, 0)); 4410 return Lret(ce, e); 4411 } 4412 else 4413 { 4414 /* The offset from cdfrom => cdto can only be determined at runtime. 4415 * Cases: 4416 * - class => derived class (downcast) 4417 * - interface => derived class (downcast) 4418 * - class => foreign interface (cross cast) 4419 * - interface => base or foreign interface (cross cast) 4420 */ 4421 int rtl = cdfrom.isInterfaceDeclaration() 4422 ? RTLSYM_INTERFACE_CAST 4423 : RTLSYM_DYNAMIC_CAST; 4424 elem *ep = el_param(el_ptr(toSymbol(cdto)), e); 4425 e = el_bin(OPcall, TYnptr, el_var(getRtlsym(rtl)), ep); 4426 } 4427 return Lret(ce, e); 4428 } 4429 4430 if (fty == Tvector && tty == Tsarray) 4431 { 4432 if (tfrom.size() == t.size()) 4433 { 4434 if (e.Eoper != OPvar && e.Eoper != OPind) 4435 { 4436 // can't perform array ops on it unless it's in memory 4437 e = addressElem(e, tfrom); 4438 e = el_una(OPind, TYarray, e); 4439 e.ET = Type_toCtype(t); 4440 } 4441 return Lret(ce, e); 4442 } 4443 } 4444 4445 ftym = tybasic(e.Ety); 4446 ttym = tybasic(totym(t)); 4447 if (ftym == ttym) 4448 return Lret(ce, e); 4449 4450 /* Reduce combinatorial explosion by rewriting the 'to' and 'from' types to a 4451 * generic equivalent (as far as casting goes) 4452 */ 4453 switch (tty) 4454 { 4455 case Tpointer: 4456 if (fty == Tdelegate) 4457 return Lpaint(ce, e, ttym); 4458 tty = irs.params.is64bit ? Tuns64 : Tuns32; 4459 break; 4460 4461 case Tchar: tty = Tuns8; break; 4462 case Twchar: tty = Tuns16; break; 4463 case Tdchar: tty = Tuns32; break; 4464 case Tvoid: return Lpaint(ce, e, ttym); 4465 4466 case Tbool: 4467 { 4468 // Construct e?true:false 4469 e = el_una(OPbool, ttym, e); 4470 return Lret(ce, e); 4471 } 4472 4473 default: 4474 break; 4475 } 4476 4477 switch (fty) 4478 { 4479 case Tnull: 4480 { 4481 // typeof(null) is same with void* in binary level. 4482 return Lzero(ce, e, ttym); 4483 } 4484 case Tpointer: fty = irs.params.is64bit ? Tuns64 : Tuns32; break; 4485 case Tchar: fty = Tuns8; break; 4486 case Twchar: fty = Tuns16; break; 4487 case Tdchar: fty = Tuns32; break; 4488 4489 default: 4490 break; 4491 } 4492 4493 static int X(int fty, int tty) { return fty * TMAX + tty; } 4494 4495 while (true) 4496 { 4497 switch (X(fty,tty)) 4498 { 4499 /* ============================= */ 4500 4501 case X(Tbool,Tint8): 4502 case X(Tbool,Tuns8): 4503 return Lpaint(ce, e, ttym); 4504 case X(Tbool,Tint16): 4505 case X(Tbool,Tuns16): 4506 case X(Tbool,Tint32): 4507 case X(Tbool,Tuns32): 4508 if (isLvalue) 4509 { 4510 eop = OPu8_16; 4511 return Leop(ce, e, eop, ttym); 4512 } 4513 else 4514 { 4515 e = el_bin(OPand, TYuchar, e, el_long(TYuchar, 1)); 4516 fty = Tuns8; 4517 continue; 4518 } 4519 4520 case X(Tbool,Tint64): 4521 case X(Tbool,Tuns64): 4522 case X(Tbool,Tfloat32): 4523 case X(Tbool,Tfloat64): 4524 case X(Tbool,Tfloat80): 4525 case X(Tbool,Tcomplex32): 4526 case X(Tbool,Tcomplex64): 4527 case X(Tbool,Tcomplex80): 4528 e = el_bin(OPand, TYuchar, e, el_long(TYuchar, 1)); 4529 fty = Tuns8; 4530 continue; 4531 4532 case X(Tbool,Timaginary32): 4533 case X(Tbool,Timaginary64): 4534 case X(Tbool,Timaginary80): 4535 return Lzero(ce, e, ttym); 4536 4537 /* ============================= */ 4538 4539 case X(Tint8,Tuns8): return Lpaint(ce, e, ttym); 4540 case X(Tint8,Tint16): 4541 case X(Tint8,Tuns16): 4542 case X(Tint8,Tint32): 4543 case X(Tint8,Tuns32): eop = OPs8_16; return Leop(ce, e, eop, ttym); 4544 case X(Tint8,Tint64): 4545 case X(Tint8,Tuns64): 4546 case X(Tint8,Tfloat32): 4547 case X(Tint8,Tfloat64): 4548 case X(Tint8,Tfloat80): 4549 case X(Tint8,Tcomplex32): 4550 case X(Tint8,Tcomplex64): 4551 case X(Tint8,Tcomplex80): 4552 e = el_una(OPs8_16, TYint, e); 4553 fty = Tint32; 4554 continue; 4555 case X(Tint8,Timaginary32): 4556 case X(Tint8,Timaginary64): 4557 case X(Tint8,Timaginary80): return Lzero(ce, e, ttym); 4558 4559 /* ============================= */ 4560 4561 case X(Tuns8,Tint8): return Lpaint(ce, e, ttym); 4562 case X(Tuns8,Tint16): 4563 case X(Tuns8,Tuns16): 4564 case X(Tuns8,Tint32): 4565 case X(Tuns8,Tuns32): eop = OPu8_16; return Leop(ce, e, eop, ttym); 4566 case X(Tuns8,Tint64): 4567 case X(Tuns8,Tuns64): 4568 case X(Tuns8,Tfloat32): 4569 case X(Tuns8,Tfloat64): 4570 case X(Tuns8,Tfloat80): 4571 case X(Tuns8,Tcomplex32): 4572 case X(Tuns8,Tcomplex64): 4573 case X(Tuns8,Tcomplex80): 4574 e = el_una(OPu8_16, TYuint, e); 4575 fty = Tuns32; 4576 continue; 4577 case X(Tuns8,Timaginary32): 4578 case X(Tuns8,Timaginary64): 4579 case X(Tuns8,Timaginary80): return Lzero(ce, e, ttym); 4580 4581 /* ============================= */ 4582 4583 case X(Tint16,Tint8): 4584 case X(Tint16,Tuns8): eop = OP16_8; return Leop(ce, e, eop, ttym); 4585 case X(Tint16,Tuns16): return Lpaint(ce, e, ttym); 4586 case X(Tint16,Tint32): 4587 case X(Tint16,Tuns32): eop = OPs16_32; return Leop(ce, e, eop, ttym); 4588 case X(Tint16,Tint64): 4589 case X(Tint16,Tuns64): e = el_una(OPs16_32, TYint, e); 4590 fty = Tint32; 4591 continue; 4592 case X(Tint16,Tfloat32): 4593 case X(Tint16,Tfloat64): 4594 case X(Tint16,Tfloat80): 4595 case X(Tint16,Tcomplex32): 4596 case X(Tint16,Tcomplex64): 4597 case X(Tint16,Tcomplex80): 4598 e = el_una(OPs16_d, TYdouble, e); 4599 fty = Tfloat64; 4600 continue; 4601 case X(Tint16,Timaginary32): 4602 case X(Tint16,Timaginary64): 4603 case X(Tint16,Timaginary80): return Lzero(ce, e, ttym); 4604 4605 /* ============================= */ 4606 4607 case X(Tuns16,Tint8): 4608 case X(Tuns16,Tuns8): eop = OP16_8; return Leop(ce, e, eop, ttym); 4609 case X(Tuns16,Tint16): return Lpaint(ce, e, ttym); 4610 case X(Tuns16,Tint32): 4611 case X(Tuns16,Tuns32): eop = OPu16_32; return Leop(ce, e, eop, ttym); 4612 case X(Tuns16,Tint64): 4613 case X(Tuns16,Tuns64): 4614 case X(Tuns16,Tfloat64): 4615 case X(Tuns16,Tfloat32): 4616 case X(Tuns16,Tfloat80): 4617 case X(Tuns16,Tcomplex32): 4618 case X(Tuns16,Tcomplex64): 4619 case X(Tuns16,Tcomplex80): 4620 e = el_una(OPu16_32, TYuint, e); 4621 fty = Tuns32; 4622 continue; 4623 case X(Tuns16,Timaginary32): 4624 case X(Tuns16,Timaginary64): 4625 case X(Tuns16,Timaginary80): return Lzero(ce, e, ttym); 4626 4627 /* ============================= */ 4628 4629 case X(Tint32,Tint8): 4630 case X(Tint32,Tuns8): e = el_una(OP32_16, TYshort, e); 4631 fty = Tint16; 4632 continue; 4633 case X(Tint32,Tint16): 4634 case X(Tint32,Tuns16): eop = OP32_16; return Leop(ce, e, eop, ttym); 4635 case X(Tint32,Tuns32): return Lpaint(ce, e, ttym); 4636 case X(Tint32,Tint64): 4637 case X(Tint32,Tuns64): eop = OPs32_64; return Leop(ce, e, eop, ttym); 4638 case X(Tint32,Tfloat32): 4639 case X(Tint32,Tfloat64): 4640 case X(Tint32,Tfloat80): 4641 case X(Tint32,Tcomplex32): 4642 case X(Tint32,Tcomplex64): 4643 case X(Tint32,Tcomplex80): 4644 e = el_una(OPs32_d, TYdouble, e); 4645 fty = Tfloat64; 4646 continue; 4647 case X(Tint32,Timaginary32): 4648 case X(Tint32,Timaginary64): 4649 case X(Tint32,Timaginary80): return Lzero(ce, e, ttym); 4650 4651 /* ============================= */ 4652 4653 case X(Tuns32,Tint8): 4654 case X(Tuns32,Tuns8): e = el_una(OP32_16, TYshort, e); 4655 fty = Tuns16; 4656 continue; 4657 case X(Tuns32,Tint16): 4658 case X(Tuns32,Tuns16): eop = OP32_16; return Leop(ce, e, eop, ttym); 4659 case X(Tuns32,Tint32): return Lpaint(ce, e, ttym); 4660 case X(Tuns32,Tint64): 4661 case X(Tuns32,Tuns64): eop = OPu32_64; return Leop(ce, e, eop, ttym); 4662 case X(Tuns32,Tfloat32): 4663 case X(Tuns32,Tfloat64): 4664 case X(Tuns32,Tfloat80): 4665 case X(Tuns32,Tcomplex32): 4666 case X(Tuns32,Tcomplex64): 4667 case X(Tuns32,Tcomplex80): 4668 e = el_una(OPu32_d, TYdouble, e); 4669 fty = Tfloat64; 4670 continue; 4671 case X(Tuns32,Timaginary32): 4672 case X(Tuns32,Timaginary64): 4673 case X(Tuns32,Timaginary80): return Lzero(ce, e, ttym); 4674 4675 /* ============================= */ 4676 4677 case X(Tint64,Tint8): 4678 case X(Tint64,Tuns8): 4679 case X(Tint64,Tint16): 4680 case X(Tint64,Tuns16): e = el_una(OP64_32, TYint, e); 4681 fty = Tint32; 4682 continue; 4683 case X(Tint64,Tint32): 4684 case X(Tint64,Tuns32): eop = OP64_32; return Leop(ce, e, eop, ttym); 4685 case X(Tint64,Tuns64): return Lpaint(ce, e, ttym); 4686 case X(Tint64,Tfloat32): 4687 case X(Tint64,Tfloat64): 4688 case X(Tint64,Tfloat80): 4689 case X(Tint64,Tcomplex32): 4690 case X(Tint64,Tcomplex64): 4691 case X(Tint64,Tcomplex80): 4692 e = el_una(OPs64_d, TYdouble, e); 4693 fty = Tfloat64; 4694 continue; 4695 case X(Tint64,Timaginary32): 4696 case X(Tint64,Timaginary64): 4697 case X(Tint64,Timaginary80): return Lzero(ce, e, ttym); 4698 4699 /* ============================= */ 4700 4701 case X(Tuns64,Tint8): 4702 case X(Tuns64,Tuns8): 4703 case X(Tuns64,Tint16): 4704 case X(Tuns64,Tuns16): e = el_una(OP64_32, TYint, e); 4705 fty = Tint32; 4706 continue; 4707 case X(Tuns64,Tint32): 4708 case X(Tuns64,Tuns32): eop = OP64_32; return Leop(ce, e, eop, ttym); 4709 case X(Tuns64,Tint64): return Lpaint(ce, e, ttym); 4710 case X(Tuns64,Tfloat32): 4711 case X(Tuns64,Tfloat64): 4712 case X(Tuns64,Tfloat80): 4713 case X(Tuns64,Tcomplex32): 4714 case X(Tuns64,Tcomplex64): 4715 case X(Tuns64,Tcomplex80): 4716 e = el_una(OPu64_d, TYdouble, e); 4717 fty = Tfloat64; 4718 continue; 4719 case X(Tuns64,Timaginary32): 4720 case X(Tuns64,Timaginary64): 4721 case X(Tuns64,Timaginary80): return Lzero(ce, e, ttym); 4722 4723 /* ============================= */ 4724 4725 case X(Tfloat32,Tint8): 4726 case X(Tfloat32,Tuns8): 4727 case X(Tfloat32,Tint16): 4728 case X(Tfloat32,Tuns16): 4729 case X(Tfloat32,Tint32): 4730 case X(Tfloat32,Tuns32): 4731 case X(Tfloat32,Tint64): 4732 case X(Tfloat32,Tuns64): 4733 case X(Tfloat32,Tfloat80): e = el_una(OPf_d, TYdouble, e); 4734 fty = Tfloat64; 4735 continue; 4736 case X(Tfloat32,Tfloat64): eop = OPf_d; return Leop(ce, e, eop, ttym); 4737 case X(Tfloat32,Timaginary32): 4738 case X(Tfloat32,Timaginary64): 4739 case X(Tfloat32,Timaginary80): return Lzero(ce, e, ttym); 4740 case X(Tfloat32,Tcomplex32): 4741 case X(Tfloat32,Tcomplex64): 4742 case X(Tfloat32,Tcomplex80): 4743 e = el_bin(OPadd,TYcfloat,el_long(TYifloat,0),e); 4744 fty = Tcomplex32; 4745 continue; 4746 4747 /* ============================= */ 4748 4749 case X(Tfloat64,Tint8): 4750 case X(Tfloat64,Tuns8): e = el_una(OPd_s16, TYshort, e); 4751 fty = Tint16; 4752 continue; 4753 case X(Tfloat64,Tint16): eop = OPd_s16; return Leop(ce, e, eop, ttym); 4754 case X(Tfloat64,Tuns16): eop = OPd_u16; return Leop(ce, e, eop, ttym); 4755 case X(Tfloat64,Tint32): eop = OPd_s32; return Leop(ce, e, eop, ttym); 4756 case X(Tfloat64,Tuns32): eop = OPd_u32; return Leop(ce, e, eop, ttym); 4757 case X(Tfloat64,Tint64): eop = OPd_s64; return Leop(ce, e, eop, ttym); 4758 case X(Tfloat64,Tuns64): eop = OPd_u64; return Leop(ce, e, eop, ttym); 4759 case X(Tfloat64,Tfloat32): eop = OPd_f; return Leop(ce, e, eop, ttym); 4760 case X(Tfloat64,Tfloat80): eop = OPd_ld; return Leop(ce, e, eop, ttym); 4761 case X(Tfloat64,Timaginary32): 4762 case X(Tfloat64,Timaginary64): 4763 case X(Tfloat64,Timaginary80): return Lzero(ce, e, ttym); 4764 case X(Tfloat64,Tcomplex32): 4765 case X(Tfloat64,Tcomplex64): 4766 case X(Tfloat64,Tcomplex80): 4767 e = el_bin(OPadd,TYcdouble,el_long(TYidouble,0),e); 4768 fty = Tcomplex64; 4769 continue; 4770 4771 /* ============================= */ 4772 4773 case X(Tfloat80,Tint8): 4774 case X(Tfloat80,Tuns8): 4775 case X(Tfloat80,Tint16): 4776 case X(Tfloat80,Tuns16): 4777 case X(Tfloat80,Tint32): 4778 case X(Tfloat80,Tuns32): 4779 case X(Tfloat80,Tint64): 4780 case X(Tfloat80,Tfloat32): e = el_una(OPld_d, TYdouble, e); 4781 fty = Tfloat64; 4782 continue; 4783 case X(Tfloat80,Tuns64): 4784 eop = OPld_u64; return Leop(ce, e, eop, ttym); 4785 case X(Tfloat80,Tfloat64): eop = OPld_d; return Leop(ce, e, eop, ttym); 4786 case X(Tfloat80,Timaginary32): 4787 case X(Tfloat80,Timaginary64): 4788 case X(Tfloat80,Timaginary80): return Lzero(ce, e, ttym); 4789 case X(Tfloat80,Tcomplex32): 4790 case X(Tfloat80,Tcomplex64): 4791 case X(Tfloat80,Tcomplex80): 4792 e = el_bin(OPadd,TYcldouble,e,el_long(TYildouble,0)); 4793 fty = Tcomplex80; 4794 continue; 4795 4796 /* ============================= */ 4797 4798 case X(Timaginary32,Tint8): 4799 case X(Timaginary32,Tuns8): 4800 case X(Timaginary32,Tint16): 4801 case X(Timaginary32,Tuns16): 4802 case X(Timaginary32,Tint32): 4803 case X(Timaginary32,Tuns32): 4804 case X(Timaginary32,Tint64): 4805 case X(Timaginary32,Tuns64): 4806 case X(Timaginary32,Tfloat32): 4807 case X(Timaginary32,Tfloat64): 4808 case X(Timaginary32,Tfloat80): return Lzero(ce, e, ttym); 4809 case X(Timaginary32,Timaginary64): eop = OPf_d; return Leop(ce, e, eop, ttym); 4810 case X(Timaginary32,Timaginary80): 4811 e = el_una(OPf_d, TYidouble, e); 4812 fty = Timaginary64; 4813 continue; 4814 case X(Timaginary32,Tcomplex32): 4815 case X(Timaginary32,Tcomplex64): 4816 case X(Timaginary32,Tcomplex80): 4817 e = el_bin(OPadd,TYcfloat,el_long(TYfloat,0),e); 4818 fty = Tcomplex32; 4819 continue; 4820 4821 /* ============================= */ 4822 4823 case X(Timaginary64,Tint8): 4824 case X(Timaginary64,Tuns8): 4825 case X(Timaginary64,Tint16): 4826 case X(Timaginary64,Tuns16): 4827 case X(Timaginary64,Tint32): 4828 case X(Timaginary64,Tuns32): 4829 case X(Timaginary64,Tint64): 4830 case X(Timaginary64,Tuns64): 4831 case X(Timaginary64,Tfloat32): 4832 case X(Timaginary64,Tfloat64): 4833 case X(Timaginary64,Tfloat80): return Lzero(ce, e, ttym); 4834 case X(Timaginary64,Timaginary32): eop = OPd_f; return Leop(ce, e, eop, ttym); 4835 case X(Timaginary64,Timaginary80): eop = OPd_ld; return Leop(ce, e, eop, ttym); 4836 case X(Timaginary64,Tcomplex32): 4837 case X(Timaginary64,Tcomplex64): 4838 case X(Timaginary64,Tcomplex80): 4839 e = el_bin(OPadd,TYcdouble,el_long(TYdouble,0),e); 4840 fty = Tcomplex64; 4841 continue; 4842 4843 /* ============================= */ 4844 4845 case X(Timaginary80,Tint8): 4846 case X(Timaginary80,Tuns8): 4847 case X(Timaginary80,Tint16): 4848 case X(Timaginary80,Tuns16): 4849 case X(Timaginary80,Tint32): 4850 case X(Timaginary80,Tuns32): 4851 case X(Timaginary80,Tint64): 4852 case X(Timaginary80,Tuns64): 4853 case X(Timaginary80,Tfloat32): 4854 case X(Timaginary80,Tfloat64): 4855 case X(Timaginary80,Tfloat80): return Lzero(ce, e, ttym); 4856 case X(Timaginary80,Timaginary32): e = el_una(OPld_d, TYidouble, e); 4857 fty = Timaginary64; 4858 continue; 4859 case X(Timaginary80,Timaginary64): eop = OPld_d; return Leop(ce, e, eop, ttym); 4860 case X(Timaginary80,Tcomplex32): 4861 case X(Timaginary80,Tcomplex64): 4862 case X(Timaginary80,Tcomplex80): 4863 e = el_bin(OPadd,TYcldouble,el_long(TYldouble,0),e); 4864 fty = Tcomplex80; 4865 continue; 4866 4867 /* ============================= */ 4868 4869 case X(Tcomplex32,Tint8): 4870 case X(Tcomplex32,Tuns8): 4871 case X(Tcomplex32,Tint16): 4872 case X(Tcomplex32,Tuns16): 4873 case X(Tcomplex32,Tint32): 4874 case X(Tcomplex32,Tuns32): 4875 case X(Tcomplex32,Tint64): 4876 case X(Tcomplex32,Tuns64): 4877 case X(Tcomplex32,Tfloat32): 4878 case X(Tcomplex32,Tfloat64): 4879 case X(Tcomplex32,Tfloat80): 4880 e = el_una(OPc_r, TYfloat, e); 4881 fty = Tfloat32; 4882 continue; 4883 case X(Tcomplex32,Timaginary32): 4884 case X(Tcomplex32,Timaginary64): 4885 case X(Tcomplex32,Timaginary80): 4886 e = el_una(OPc_i, TYifloat, e); 4887 fty = Timaginary32; 4888 continue; 4889 case X(Tcomplex32,Tcomplex64): 4890 case X(Tcomplex32,Tcomplex80): 4891 e = el_una(OPf_d, TYcdouble, e); 4892 fty = Tcomplex64; 4893 continue; 4894 4895 /* ============================= */ 4896 4897 case X(Tcomplex64,Tint8): 4898 case X(Tcomplex64,Tuns8): 4899 case X(Tcomplex64,Tint16): 4900 case X(Tcomplex64,Tuns16): 4901 case X(Tcomplex64,Tint32): 4902 case X(Tcomplex64,Tuns32): 4903 case X(Tcomplex64,Tint64): 4904 case X(Tcomplex64,Tuns64): 4905 case X(Tcomplex64,Tfloat32): 4906 case X(Tcomplex64,Tfloat64): 4907 case X(Tcomplex64,Tfloat80): 4908 e = el_una(OPc_r, TYdouble, e); 4909 fty = Tfloat64; 4910 continue; 4911 case X(Tcomplex64,Timaginary32): 4912 case X(Tcomplex64,Timaginary64): 4913 case X(Tcomplex64,Timaginary80): 4914 e = el_una(OPc_i, TYidouble, e); 4915 fty = Timaginary64; 4916 continue; 4917 case X(Tcomplex64,Tcomplex32): eop = OPd_f; return Leop(ce, e, eop, ttym); 4918 case X(Tcomplex64,Tcomplex80): eop = OPd_ld; return Leop(ce, e, eop, ttym); 4919 4920 /* ============================= */ 4921 4922 case X(Tcomplex80,Tint8): 4923 case X(Tcomplex80,Tuns8): 4924 case X(Tcomplex80,Tint16): 4925 case X(Tcomplex80,Tuns16): 4926 case X(Tcomplex80,Tint32): 4927 case X(Tcomplex80,Tuns32): 4928 case X(Tcomplex80,Tint64): 4929 case X(Tcomplex80,Tuns64): 4930 case X(Tcomplex80,Tfloat32): 4931 case X(Tcomplex80,Tfloat64): 4932 case X(Tcomplex80,Tfloat80): 4933 e = el_una(OPc_r, TYldouble, e); 4934 fty = Tfloat80; 4935 continue; 4936 case X(Tcomplex80,Timaginary32): 4937 case X(Tcomplex80,Timaginary64): 4938 case X(Tcomplex80,Timaginary80): 4939 e = el_una(OPc_i, TYildouble, e); 4940 fty = Timaginary80; 4941 continue; 4942 case X(Tcomplex80,Tcomplex32): 4943 case X(Tcomplex80,Tcomplex64): 4944 e = el_una(OPld_d, TYcdouble, e); 4945 fty = Tcomplex64; 4946 continue; 4947 4948 /* ============================= */ 4949 4950 default: 4951 if (fty == tty) 4952 return Lpaint(ce, e, ttym); 4953 //dump(0); 4954 //printf("fty = %d, tty = %d, %d\n", fty, tty, t.ty); 4955 // This error should really be pushed to the front end 4956 ce.error("e2ir: cannot cast `%s` of type `%s` to type `%s`", ce.e1.toChars(), ce.e1.type.toChars(), t.toChars()); 4957 e = el_long(TYint, 0); 4958 return e; 4959 4960 } 4961 } 4962 } 4963 4964 override void visit(ArrayLengthExp ale) 4965 { 4966 elem *e = toElem(ale.e1, irs); 4967 e = el_una(irs.params.is64bit ? OP128_64 : OP64_32, totym(ale.type), e); 4968 elem_setLoc(e, ale.loc); 4969 result = e; 4970 } 4971 4972 override void visit(DelegatePtrExp dpe) 4973 { 4974 // *cast(void**)(&dg) 4975 elem *e = toElem(dpe.e1, irs); 4976 Type tb1 = dpe.e1.type.toBasetype(); 4977 e = addressElem(e, tb1); 4978 e = el_una(OPind, totym(dpe.type), e); 4979 elem_setLoc(e, dpe.loc); 4980 result = e; 4981 } 4982 4983 override void visit(DelegateFuncptrExp dfpe) 4984 { 4985 // *cast(void**)(&dg + size_t.sizeof) 4986 elem *e = toElem(dfpe.e1, irs); 4987 Type tb1 = dfpe.e1.type.toBasetype(); 4988 e = addressElem(e, tb1); 4989 e = el_bin(OPadd, TYnptr, e, el_long(TYsize_t, irs.params.is64bit ? 8 : 4)); 4990 e = el_una(OPind, totym(dfpe.type), e); 4991 elem_setLoc(e, dfpe.loc); 4992 result = e; 4993 } 4994 4995 override void visit(SliceExp se) 4996 { 4997 //printf("SliceExp.toElem() se = %s %s\n", se.type.toChars(), se.toChars()); 4998 Type tb = se.type.toBasetype(); 4999 assert(tb.ty == Tarray || tb.ty == Tsarray); 5000 Type t1 = se.e1.type.toBasetype(); 5001 elem *e = toElem(se.e1, irs); 5002 if (se.lwr) 5003 { 5004 uint sz = cast(uint)t1.nextOf().size(); 5005 5006 elem *einit = resolveLengthVar(se.lengthVar, &e, t1); 5007 if (t1.ty == Tsarray) 5008 e = array_toPtr(se.e1.type, e); 5009 if (!einit) 5010 { 5011 einit = e; 5012 e = el_same(&einit); 5013 } 5014 // e is a temporary, typed: 5015 // TYdarray if t.ty == Tarray 5016 // TYptr if t.ty == Tsarray or Tpointer 5017 5018 elem *elwr = toElem(se.lwr, irs); 5019 elem *eupr = toElem(se.upr, irs); 5020 elem *elwr2 = el_sideeffect(eupr) ? el_copytotmp(&elwr) : el_same(&elwr); 5021 elem *eupr2 = eupr; 5022 5023 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", se.upperIsInBounds, se.lowerIsLessThanUpper); 5024 if (irs.arrayBoundsCheck()) 5025 { 5026 // Checks (unsigned compares): 5027 // upr <= array.length 5028 // lwr <= upr 5029 5030 elem *c1 = null; 5031 elem *elen; 5032 if (!se.upperIsInBounds) 5033 { 5034 eupr2 = el_same(&eupr); 5035 eupr2.Ety = TYsize_t; // make sure unsigned comparison 5036 5037 if (auto tsa = t1.isTypeSArray()) 5038 { 5039 elen = el_long(TYsize_t, tsa.dim.toInteger()); 5040 } 5041 else if (t1.ty == Tarray) 5042 { 5043 if (se.lengthVar && !(se.lengthVar.storage_class & STC.const_)) 5044 elen = el_var(toSymbol(se.lengthVar)); 5045 else 5046 { 5047 elen = e; 5048 e = el_same(&elen); 5049 elen = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, elen); 5050 } 5051 } 5052 5053 c1 = el_bin(OPle, TYint, eupr, elen); 5054 5055 if (!se.lowerIsLessThanUpper) 5056 { 5057 c1 = el_bin(OPandand, TYint, 5058 c1, el_bin(OPle, TYint, elwr2, eupr2)); 5059 elwr2 = el_copytree(elwr2); 5060 eupr2 = el_copytree(eupr2); 5061 } 5062 } 5063 else if (!se.lowerIsLessThanUpper) 5064 { 5065 eupr2 = el_same(&eupr); 5066 eupr2.Ety = TYsize_t; // make sure unsigned comparison 5067 5068 c1 = el_bin(OPle, TYint, elwr2, eupr); 5069 elwr2 = el_copytree(elwr2); 5070 } 5071 5072 if (c1) 5073 { 5074 // Construct: (c1 || arrayBoundsError) 5075 auto ea = buildArrayBoundsError(irs, se.loc, el_copytree(elwr2), el_copytree(eupr2), el_copytree(elen)); 5076 elem *eb = el_bin(OPoror, TYvoid, c1, ea); 5077 5078 elwr = el_combine(elwr, eb); 5079 } 5080 } 5081 if (t1.ty != Tsarray) 5082 e = array_toPtr(se.e1.type, e); 5083 5084 // Create an array reference where: 5085 // length is (upr - lwr) 5086 // pointer is (ptr + lwr*sz) 5087 // Combine as (length pair ptr) 5088 5089 elem *eofs = el_bin(OPmul, TYsize_t, elwr2, el_long(TYsize_t, sz)); 5090 elem *eptr = el_bin(OPadd, TYnptr, e, eofs); 5091 5092 if (tb.ty == Tarray) 5093 { 5094 elem *elen = el_bin(OPmin, TYsize_t, eupr2, el_copytree(elwr2)); 5095 e = el_pair(TYdarray, elen, eptr); 5096 } 5097 else 5098 { 5099 assert(tb.ty == Tsarray); 5100 e = el_una(OPind, totym(se.type), eptr); 5101 if (tybasic(e.Ety) == TYstruct) 5102 e.ET = Type_toCtype(se.type); 5103 } 5104 e = el_combine(elwr, e); 5105 e = el_combine(einit, e); 5106 //elem_print(e); 5107 } 5108 else if (t1.ty == Tsarray && tb.ty == Tarray) 5109 { 5110 e = sarray_toDarray(se.loc, t1, null, e); 5111 } 5112 else 5113 { 5114 assert(t1.ty == tb.ty); // Tarray or Tsarray 5115 5116 // https://issues.dlang.org/show_bug.cgi?id=14672 5117 // If se is in left side operand of element-wise 5118 // assignment, the element type can be painted to the base class. 5119 int offset; 5120 assert(t1.nextOf().equivalent(tb.nextOf()) || 5121 tb.nextOf().isBaseOf(t1.nextOf(), &offset) && offset == 0); 5122 } 5123 elem_setLoc(e, se.loc); 5124 result = e; 5125 } 5126 5127 override void visit(IndexExp ie) 5128 { 5129 elem *e; 5130 elem *n1 = toElem(ie.e1, irs); 5131 elem *eb = null; 5132 5133 //printf("IndexExp.toElem() %s\n", ie.toChars()); 5134 Type t1 = ie.e1.type.toBasetype(); 5135 if (auto taa = t1.isTypeAArray()) 5136 { 5137 // set to: 5138 // *aaGetY(aa, aati, valuesize, &key); 5139 // or 5140 // *aaGetRvalueX(aa, keyti, valuesize, &key); 5141 5142 uint vsize = cast(uint)taa.next.size(); 5143 5144 // n2 becomes the index, also known as the key 5145 elem *n2 = toElem(ie.e2, irs); 5146 5147 /* Turn n2 into a pointer to the index. If it's an lvalue, 5148 * take the address of it. If not, copy it to a temp and 5149 * take the address of that. 5150 */ 5151 n2 = addressElem(n2, taa.index); 5152 5153 elem *valuesize = el_long(TYsize_t, vsize); 5154 //printf("valuesize: "); elem_print(valuesize); 5155 Symbol *s; 5156 elem *ti; 5157 if (ie.modifiable) 5158 { 5159 n1 = el_una(OPaddr, TYnptr, n1); 5160 s = aaGetSymbol(taa, "GetY", 1); 5161 ti = getTypeInfo(ie.e1.loc, taa.unSharedOf().mutableOf(), irs); 5162 } 5163 else 5164 { 5165 s = aaGetSymbol(taa, "GetRvalueX", 1); 5166 ti = getTypeInfo(ie.e1.loc, taa.index, irs); 5167 } 5168 //printf("taa.index = %s\n", taa.index.toChars()); 5169 //printf("ti:\n"); elem_print(ti); 5170 elem *ep = el_params(n2, valuesize, ti, n1, null); 5171 e = el_bin(OPcall, TYnptr, el_var(s), ep); 5172 if (irs.arrayBoundsCheck()) 5173 { 5174 elem *n = el_same(&e); 5175 5176 // Construct: ((e || arrayBoundsError), n) 5177 auto ea = buildArrayBoundsError(irs, ie.loc, null, null, null); // FIXME 5178 e = el_bin(OPoror,TYvoid,e,ea); 5179 e = el_bin(OPcomma, TYnptr, e, n); 5180 } 5181 e = el_una(OPind, totym(ie.type), e); 5182 if (tybasic(e.Ety) == TYstruct) 5183 e.ET = Type_toCtype(ie.type); 5184 } 5185 else 5186 { 5187 elem *einit = resolveLengthVar(ie.lengthVar, &n1, t1); 5188 elem *n2 = toElem(ie.e2, irs); 5189 5190 if (irs.arrayBoundsCheck() && !ie.indexIsInBounds) 5191 { 5192 elem *elength; 5193 5194 if (auto tsa = t1.isTypeSArray()) 5195 { 5196 const length = tsa.dim.toInteger(); 5197 5198 elength = el_long(TYsize_t, length); 5199 goto L1; 5200 } 5201 else if (t1.ty == Tarray) 5202 { 5203 elength = n1; 5204 n1 = el_same(&elength); 5205 elength = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, elength); 5206 L1: 5207 elem *n2x = n2; 5208 n2 = el_same(&n2x); 5209 n2x = el_bin(OPlt, TYint, n2x, elength); 5210 5211 // Construct: (n2x || arrayBoundsError) 5212 auto ea = buildArrayBoundsError(irs, ie.loc, null, el_copytree(n2), el_copytree(elength)); 5213 eb = el_bin(OPoror,TYvoid,n2x,ea); 5214 } 5215 } 5216 5217 n1 = array_toPtr(t1, n1); 5218 5219 { 5220 elem *escale = el_long(TYsize_t, t1.nextOf().size()); 5221 n2 = el_bin(OPmul, TYsize_t, n2, escale); 5222 e = el_bin(OPadd, TYnptr, n1, n2); 5223 e = el_una(OPind, totym(ie.type), e); 5224 if (tybasic(e.Ety) == TYstruct || tybasic(e.Ety) == TYarray) 5225 { 5226 e.Ety = TYstruct; 5227 e.ET = Type_toCtype(ie.type); 5228 } 5229 } 5230 5231 eb = el_combine(einit, eb); 5232 e = el_combine(eb, e); 5233 } 5234 elem_setLoc(e, ie.loc); 5235 result = e; 5236 } 5237 5238 5239 override void visit(TupleExp te) 5240 { 5241 //printf("TupleExp.toElem() %s\n", te.toChars()); 5242 elem *e = null; 5243 if (te.e0) 5244 e = toElem(te.e0, irs); 5245 foreach (el; *te.exps) 5246 { 5247 elem *ep = toElem(el, irs); 5248 e = el_combine(e, ep); 5249 } 5250 result = e; 5251 } 5252 5253 static elem *tree_insert(Elems *args, size_t low, size_t high) 5254 { 5255 assert(low < high); 5256 if (low + 1 == high) 5257 return (*args)[low]; 5258 int mid = cast(int)((low + high) >> 1); 5259 return el_param(tree_insert(args, low, mid), 5260 tree_insert(args, mid, high)); 5261 } 5262 5263 override void visit(ArrayLiteralExp ale) 5264 { 5265 size_t dim = ale.elements ? ale.elements.dim : 0; 5266 5267 //printf("ArrayLiteralExp.toElem() %s, type = %s\n", ale.toChars(), ale.type.toChars()); 5268 Type tb = ale.type.toBasetype(); 5269 if (tb.ty == Tsarray && tb.nextOf().toBasetype().ty == Tvoid) 5270 { 5271 // Convert void[n] to ubyte[n] 5272 tb = Type.tuns8.sarrayOf((cast(TypeSArray)tb).dim.toUInteger()); 5273 } 5274 5275 elem *e; 5276 if (tb.ty == Tsarray && dim) 5277 { 5278 Symbol *stmp = null; 5279 e = ExpressionsToStaticArray(ale.loc, ale.elements, &stmp, 0, ale.basis); 5280 e = el_combine(e, el_ptr(stmp)); 5281 } 5282 else if (ale.elements) 5283 { 5284 /* Instead of passing the initializers on the stack, allocate the 5285 * array and assign the members inline. 5286 * Avoids the whole variadic arg mess. 5287 */ 5288 5289 // call _d_arrayliteralTX(ti, dim) 5290 e = el_bin(OPcall, TYnptr, 5291 el_var(getRtlsym(RTLSYM_ARRAYLITERALTX)), 5292 el_param(el_long(TYsize_t, dim), getTypeInfo(ale.loc, ale.type, irs))); 5293 toTraceGC(irs, e, ale.loc); 5294 5295 Symbol *stmp = symbol_genauto(Type_toCtype(Type.tvoid.pointerTo())); 5296 e = el_bin(OPeq, TYnptr, el_var(stmp), e); 5297 5298 /* Note: Even if dm == 0, the druntime function will be called so 5299 * GC heap may be allocated. However, currently it's implemented 5300 * to return null for 0 length. 5301 */ 5302 if (dim) 5303 e = el_combine(e, ExpressionsToStaticArray(ale.loc, ale.elements, &stmp, 0, ale.basis)); 5304 5305 e = el_combine(e, el_var(stmp)); 5306 } 5307 else 5308 { 5309 e = el_long(TYsize_t, 0); 5310 } 5311 5312 if (tb.ty == Tarray) 5313 { 5314 e = el_pair(TYdarray, el_long(TYsize_t, dim), e); 5315 } 5316 else if (tb.ty == Tpointer) 5317 { 5318 } 5319 else 5320 { 5321 e = el_una(OPind, TYstruct, e); 5322 e.ET = Type_toCtype(ale.type); 5323 } 5324 5325 elem_setLoc(e, ale.loc); 5326 result = e; 5327 } 5328 5329 /************************************** 5330 * Mirrors logic in Dsymbol_canThrow(). 5331 */ 5332 elem *Dsymbol_toElem(Dsymbol s) 5333 { 5334 elem *e = null; 5335 5336 void symbolDg(Dsymbol s) 5337 { 5338 e = el_combine(e, Dsymbol_toElem(s)); 5339 } 5340 5341 //printf("Dsymbol_toElem() %s\n", s.toChars()); 5342 if (auto vd = s.isVarDeclaration()) 5343 { 5344 s = s.toAlias(); 5345 if (s != vd) 5346 return Dsymbol_toElem(s); 5347 if (vd.storage_class & STC.manifest) 5348 return null; 5349 else if (vd.isStatic() || vd.storage_class & (STC.extern_ | STC.tls | STC.gshared)) 5350 toObjFile(vd, false); 5351 else 5352 { 5353 Symbol *sp = toSymbol(s); 5354 symbol_add(sp); 5355 //printf("\tadding symbol '%s'\n", sp.Sident); 5356 if (vd._init) 5357 { 5358 if (auto ie = vd._init.isExpInitializer()) 5359 e = toElem(ie.exp, irs); 5360 } 5361 5362 /* Mark the point of construction of a variable that needs to be destructed. 5363 */ 5364 if (vd.needsScopeDtor()) 5365 { 5366 elem *edtor = toElem(vd.edtor, irs); 5367 elem *ed = null; 5368 if (irs.isNothrow()) 5369 { 5370 ed = edtor; 5371 } 5372 else 5373 { 5374 // Construct special elems to deal with exceptions 5375 e = el_ctor_dtor(e, edtor, &ed); 5376 } 5377 5378 // ed needs to be inserted into the code later 5379 irs.varsInScope.push(ed); 5380 } 5381 } 5382 } 5383 else if (auto cd = s.isClassDeclaration()) 5384 { 5385 irs.deferToObj.push(s); 5386 } 5387 else if (auto sd = s.isStructDeclaration()) 5388 { 5389 irs.deferToObj.push(sd); 5390 } 5391 else if (auto fd = s.isFuncDeclaration()) 5392 { 5393 //printf("function %s\n", fd.toChars()); 5394 irs.deferToObj.push(fd); 5395 } 5396 else if (auto ad = s.isAttribDeclaration()) 5397 { 5398 ad.include(null).foreachDsymbol(&symbolDg); 5399 } 5400 else if (auto tm = s.isTemplateMixin()) 5401 { 5402 //printf("%s\n", tm.toChars()); 5403 tm.members.foreachDsymbol(&symbolDg); 5404 } 5405 else if (auto td = s.isTupleDeclaration()) 5406 { 5407 foreach (o; *td.objects) 5408 { 5409 if (o.dyncast() == DYNCAST.expression) 5410 { Expression eo = cast(Expression)o; 5411 if (eo.op == TOK.dSymbol) 5412 { DsymbolExp se = cast(DsymbolExp)eo; 5413 e = el_combine(e, Dsymbol_toElem(se.s)); 5414 } 5415 } 5416 } 5417 } 5418 else if (auto ed = s.isEnumDeclaration()) 5419 { 5420 irs.deferToObj.push(ed); 5421 } 5422 else if (auto ti = s.isTemplateInstance()) 5423 { 5424 irs.deferToObj.push(ti); 5425 } 5426 return e; 5427 } 5428 5429 /************************************************* 5430 * Allocate a static array, and initialize its members with elems[]. 5431 * Return the initialization expression, and the symbol for the static array in *psym. 5432 */ 5433 elem *ElemsToStaticArray(const ref Loc loc, Type telem, Elems *elems, Symbol **psym) 5434 { 5435 // Create a static array of type telem[dim] 5436 const dim = elems.dim; 5437 assert(dim); 5438 5439 Type tsarray = telem.sarrayOf(dim); 5440 const szelem = telem.size(); 5441 .type *te = Type_toCtype(telem); // stmp[] element type 5442 5443 Symbol *stmp = symbol_genauto(Type_toCtype(tsarray)); 5444 *psym = stmp; 5445 5446 elem *e = null; 5447 foreach (i, ep; *elems) 5448 { 5449 /* Generate: *(&stmp + i * szelem) = element[i] 5450 */ 5451 elem *ev = el_ptr(stmp); 5452 ev = el_bin(OPadd, TYnptr, ev, el_long(TYsize_t, i * szelem)); 5453 ev = el_una(OPind, te.Tty, ev); 5454 elem *eeq = elAssign(ev, ep, null, te); 5455 e = el_combine(e, eeq); 5456 } 5457 return e; 5458 } 5459 5460 /************************************************* 5461 * Allocate a static array, and initialize its members with 5462 * exps[]. 5463 * Return the initialization expression, and the symbol for the static array in *psym. 5464 */ 5465 elem *ExpressionsToStaticArray(const ref Loc loc, Expressions *exps, Symbol **psym, size_t offset = 0, Expression basis = null) 5466 { 5467 // Create a static array of type telem[dim] 5468 const dim = exps.dim; 5469 assert(dim); 5470 5471 Type telem = ((*exps)[0] ? (*exps)[0] : basis).type; 5472 const szelem = telem.size(); 5473 .type *te = Type_toCtype(telem); // stmp[] element type 5474 5475 if (!*psym) 5476 { 5477 Type tsarray2 = telem.sarrayOf(dim); 5478 *psym = symbol_genauto(Type_toCtype(tsarray2)); 5479 offset = 0; 5480 } 5481 Symbol *stmp = *psym; 5482 5483 elem *e = null; 5484 for (size_t i = 0; i < dim; ) 5485 { 5486 Expression el = (*exps)[i]; 5487 if (!el) 5488 el = basis; 5489 if (el.op == TOK.arrayLiteral && 5490 el.type.toBasetype().ty == Tsarray) 5491 { 5492 ArrayLiteralExp ale = cast(ArrayLiteralExp)el; 5493 if (ale.elements && ale.elements.dim) 5494 { 5495 elem *ex = ExpressionsToStaticArray( 5496 ale.loc, ale.elements, &stmp, cast(uint)(offset + i * szelem), ale.basis); 5497 e = el_combine(e, ex); 5498 } 5499 i++; 5500 continue; 5501 } 5502 5503 size_t j = i + 1; 5504 if (el.isConst() || el.op == TOK.null_) 5505 { 5506 // If the trivial elements are same values, do memcpy. 5507 while (j < dim) 5508 { 5509 Expression en = (*exps)[j]; 5510 if (!en) 5511 en = basis; 5512 if (!el.equals(en)) 5513 break; 5514 j++; 5515 } 5516 } 5517 5518 /* Generate: *(&stmp + i * szelem) = element[i] 5519 */ 5520 elem *ep = toElem(el, irs); 5521 elem *ev = tybasic(stmp.Stype.Tty) == TYnptr ? el_var(stmp) : el_ptr(stmp); 5522 ev = el_bin(OPadd, TYnptr, ev, el_long(TYsize_t, offset + i * szelem)); 5523 5524 elem *eeq; 5525 if (j == i + 1) 5526 { 5527 ev = el_una(OPind, te.Tty, ev); 5528 eeq = elAssign(ev, ep, null, te); 5529 } 5530 else 5531 { 5532 elem *edim = el_long(TYsize_t, j - i); 5533 eeq = setArray(el, ev, edim, telem, ep, irs, TOK.blit); 5534 } 5535 e = el_combine(e, eeq); 5536 i = j; 5537 } 5538 return e; 5539 } 5540 5541 override void visit(AssocArrayLiteralExp aale) 5542 { 5543 //printf("AssocArrayLiteralExp.toElem() %s\n", aale.toChars()); 5544 5545 Type t = aale.type.toBasetype().mutableOf(); 5546 5547 size_t dim = aale.keys.dim; 5548 if (dim) 5549 { 5550 // call _d_assocarrayliteralTX(TypeInfo_AssociativeArray ti, void[] keys, void[] values) 5551 // Prefer this to avoid the varargs fiasco in 64 bit code 5552 5553 assert(t.ty == Taarray); 5554 Type ta = t; 5555 5556 Symbol *skeys = null; 5557 elem *ekeys = ExpressionsToStaticArray(aale.loc, aale.keys, &skeys); 5558 5559 Symbol *svalues = null; 5560 elem *evalues = ExpressionsToStaticArray(aale.loc, aale.values, &svalues); 5561 5562 elem *ev = el_pair(TYdarray, el_long(TYsize_t, dim), el_ptr(svalues)); 5563 elem *ek = el_pair(TYdarray, el_long(TYsize_t, dim), el_ptr(skeys )); 5564 if (config.exe == EX_WIN64) 5565 { 5566 ev = addressElem(ev, Type.tvoid.arrayOf()); 5567 ek = addressElem(ek, Type.tvoid.arrayOf()); 5568 } 5569 elem *e = el_params(ev, ek, 5570 getTypeInfo(aale.loc, ta, irs), 5571 null); 5572 5573 // call _d_assocarrayliteralTX(ti, keys, values) 5574 e = el_bin(OPcall,TYnptr,el_var(getRtlsym(RTLSYM_ASSOCARRAYLITERALTX)),e); 5575 toTraceGC(irs, e, aale.loc); 5576 if (t != ta) 5577 e = addressElem(e, ta); 5578 elem_setLoc(e, aale.loc); 5579 5580 e = el_combine(evalues, e); 5581 e = el_combine(ekeys, e); 5582 result = e; 5583 return; 5584 } 5585 else 5586 { 5587 elem *e = el_long(TYnptr, 0); // empty associative array is the null pointer 5588 if (t.ty != Taarray) 5589 e = addressElem(e, Type.tvoidptr); 5590 result = e; 5591 return; 5592 } 5593 } 5594 5595 override void visit(StructLiteralExp sle) 5596 { 5597 //printf("[%s] StructLiteralExp.toElem() %s\n", sle.loc.toChars(), sle.toChars()); 5598 result = toElemStructLit(sle, irs, TOK.construct, sle.sym, true); 5599 } 5600 5601 override void visit(ObjcClassReferenceExp e) 5602 { 5603 result = objc.toElem(e); 5604 } 5605 5606 /*****************************************************/ 5607 /* CTFE stuff */ 5608 /*****************************************************/ 5609 5610 override void visit(ClassReferenceExp e) 5611 { 5612 //printf("ClassReferenceExp.toElem() %p, value=%p, %s\n", e, e.value, e.toChars()); 5613 result = el_ptr(toSymbol(e)); 5614 } 5615 } 5616 5617 scope v = new ToElemVisitor(irs); 5618 e.accept(v); 5619 return v.result; 5620 } 5621 5622 /******************************************* 5623 * Generate elem to zero fill contents of Symbol stmp 5624 * from *poffset..offset2. 5625 * May store anywhere from 0..maxoff, as this function 5626 * tries to use aligned int stores whereever possible. 5627 * Update *poffset to end of initialized hole; *poffset will be >= offset2. 5628 */ 5629 private elem *fillHole(Symbol *stmp, size_t *poffset, size_t offset2, size_t maxoff) 5630 { 5631 elem *e = null; 5632 bool basealign = true; 5633 5634 while (*poffset < offset2) 5635 { 5636 elem *e1; 5637 if (tybasic(stmp.Stype.Tty) == TYnptr) 5638 e1 = el_var(stmp); 5639 else 5640 e1 = el_ptr(stmp); 5641 if (basealign) 5642 *poffset &= ~3; 5643 basealign = true; 5644 size_t sz = maxoff - *poffset; 5645 tym_t ty; 5646 switch (sz) 5647 { 5648 case 1: ty = TYchar; break; 5649 case 2: ty = TYshort; break; 5650 case 3: 5651 ty = TYshort; 5652 basealign = false; 5653 break; 5654 default: 5655 ty = TYlong; 5656 // TODO: OPmemset is better if sz is much bigger than 4? 5657 break; 5658 } 5659 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, *poffset)); 5660 e1 = el_una(OPind, ty, e1); 5661 e1 = el_bin(OPeq, ty, e1, el_long(ty, 0)); 5662 e = el_combine(e, e1); 5663 *poffset += tysize(ty); 5664 } 5665 return e; 5666 } 5667 5668 /************************************************* 5669 * Params: 5670 * op = TOK.assign, TOK.construct, TOK.blit 5671 * fillHoles = Fill in alignment holes with zero. Set to 5672 * false if allocated by operator new, as the holes are already zeroed. 5673 */ 5674 5675 private elem *toElemStructLit(StructLiteralExp sle, IRState *irs, TOK op, Symbol *sym, bool fillHoles) 5676 { 5677 //printf("[%s] StructLiteralExp.toElem() %s\n", sle.loc.toChars(), sle.toChars()); 5678 //printf("\tblit = %s, sym = %p fillHoles = %d\n", op == TOK.blit, sym, fillHoles); 5679 5680 if (sle.useStaticInit) 5681 { 5682 /* Use the struct declaration's init symbol 5683 */ 5684 elem *e = el_var(toInitializer(sle.sd)); 5685 e.ET = Type_toCtype(sle.sd.type); 5686 elem_setLoc(e, sle.loc); 5687 5688 if (sym) 5689 { 5690 elem *ev = el_var(sym); 5691 if (tybasic(ev.Ety) == TYnptr) 5692 ev = el_una(OPind, e.Ety, ev); 5693 ev.ET = e.ET; 5694 e = elAssign(ev, e, null, ev.ET); 5695 5696 //ev = el_var(sym); 5697 //ev.ET = e.ET; 5698 //e = el_combine(e, ev); 5699 elem_setLoc(e, sle.loc); 5700 } 5701 return e; 5702 } 5703 5704 // struct symbol to initialize with the literal 5705 Symbol *stmp = sym ? sym : symbol_genauto(Type_toCtype(sle.sd.type)); 5706 5707 elem *e = null; 5708 5709 /* If a field has explicit initializer (*sle.elements)[i] != null), 5710 * any other overlapped fields won't have initializer. It's asserted by 5711 * StructDeclaration.fill() function. 5712 * 5713 * union U { int x; long y; } 5714 * U u1 = U(1); // elements = [`1`, null] 5715 * U u2 = {y:2}; // elements = [null, `2`]; 5716 * U u3 = U(1, 2); // error 5717 * U u4 = {x:1, y:2}; // error 5718 */ 5719 size_t dim = sle.elements ? sle.elements.dim : 0; 5720 assert(dim <= sle.sd.fields.dim); 5721 5722 if (fillHoles) 5723 { 5724 /* Initialize all alignment 'holes' to zero. 5725 * Do before initializing fields, as the hole filling process 5726 * can spill over into the fields. 5727 */ 5728 const size_t structsize = sle.sd.structsize; 5729 size_t offset = 0; 5730 //printf("-- %s - fillHoles, structsize = %d\n", sle.toChars(), structsize); 5731 for (size_t i = 0; i < sle.sd.fields.dim && offset < structsize; ) 5732 { 5733 VarDeclaration v = sle.sd.fields[i]; 5734 5735 /* If the field v has explicit initializer, [offset .. v.offset] 5736 * is a hole divided by the initializer. 5737 * However if the field size is zero (e.g. int[0] v;), we can merge 5738 * the two holes in the front and the back of the field v. 5739 */ 5740 if (i < dim && (*sle.elements)[i] && v.type.size()) 5741 { 5742 //if (offset != v.offset) printf(" 1 fillHole, %d .. %d\n", offset, v.offset); 5743 e = el_combine(e, fillHole(stmp, &offset, v.offset, structsize)); 5744 offset = cast(uint)(v.offset + v.type.size()); 5745 i++; 5746 continue; 5747 } 5748 if (!v.overlapped) 5749 { 5750 i++; 5751 continue; 5752 } 5753 5754 /* AggregateDeclaration.fields holds the fields by the lexical order. 5755 * This code will minimize each hole sizes. For example: 5756 * 5757 * struct S { 5758 * union { uint f1; ushort f2; } // f1: 0..4, f2: 0..2 5759 * union { uint f3; ulong f4; } // f3: 8..12, f4: 8..16 5760 * } 5761 * S s = {f2:x, f3:y}; // filled holes: 2..8 and 12..16 5762 */ 5763 size_t vend = sle.sd.fields.dim; 5764 size_t holeEnd = structsize; 5765 size_t offset2 = structsize; 5766 foreach (j; i + 1 .. vend) 5767 { 5768 VarDeclaration vx = sle.sd.fields[j]; 5769 if (!vx.overlapped) 5770 { 5771 vend = j; 5772 break; 5773 } 5774 if (j < dim && (*sle.elements)[j] && vx.type.size()) 5775 { 5776 // Find the lowest end offset of the hole. 5777 if (offset <= vx.offset && vx.offset < holeEnd) 5778 { 5779 holeEnd = vx.offset; 5780 offset2 = cast(uint)(vx.offset + vx.type.size()); 5781 } 5782 } 5783 } 5784 if (holeEnd < structsize) 5785 { 5786 //if (offset != holeEnd) printf(" 2 fillHole, %d .. %d\n", offset, holeEnd); 5787 e = el_combine(e, fillHole(stmp, &offset, holeEnd, structsize)); 5788 offset = offset2; 5789 continue; 5790 } 5791 i = vend; 5792 } 5793 //if (offset != sle.sd.structsize) printf(" 3 fillHole, %d .. %d\n", offset, sle.sd.structsize); 5794 e = el_combine(e, fillHole(stmp, &offset, sle.sd.structsize, sle.sd.structsize)); 5795 } 5796 5797 // CTFE may fill the hidden pointer by NullExp. 5798 { 5799 foreach (i, el; *sle.elements) 5800 { 5801 if (!el) 5802 continue; 5803 5804 VarDeclaration v = sle.sd.fields[i]; 5805 assert(!v.isThisDeclaration() || el.op == TOK.null_); 5806 5807 elem *e1; 5808 if (tybasic(stmp.Stype.Tty) == TYnptr) 5809 { 5810 e1 = el_var(stmp); 5811 } 5812 else 5813 { 5814 e1 = el_ptr(stmp); 5815 } 5816 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset)); 5817 5818 elem *ep = toElem(el, irs); 5819 5820 Type t1b = v.type.toBasetype(); 5821 Type t2b = el.type.toBasetype(); 5822 if (t1b.ty == Tsarray) 5823 { 5824 if (t2b.implicitConvTo(t1b)) 5825 { 5826 elem *esize = el_long(TYsize_t, t1b.size()); 5827 ep = array_toPtr(el.type, ep); 5828 e1 = el_bin(OPmemcpy, TYnptr, e1, el_param(ep, esize)); 5829 } 5830 else 5831 { 5832 elem *edim = el_long(TYsize_t, t1b.size() / t2b.size()); 5833 e1 = setArray(el, e1, edim, t2b, ep, irs, op == TOK.construct ? TOK.blit : op); 5834 } 5835 } 5836 else 5837 { 5838 tym_t ty = totym(v.type); 5839 e1 = el_una(OPind, ty, e1); 5840 if (tybasic(ty) == TYstruct) 5841 e1.ET = Type_toCtype(v.type); 5842 e1 = elAssign(e1, ep, v.type, e1.ET); 5843 } 5844 e = el_combine(e, e1); 5845 } 5846 } 5847 5848 if (sle.sd.isNested() && dim != sle.sd.fields.dim) 5849 { 5850 // Initialize the hidden 'this' pointer 5851 assert(sle.sd.fields.dim); 5852 5853 elem* e1, e2; 5854 if (tybasic(stmp.Stype.Tty) == TYnptr) 5855 { 5856 e1 = el_var(stmp); 5857 } 5858 else 5859 { 5860 e1 = el_ptr(stmp); 5861 } 5862 if (sle.sd.vthis2) 5863 { 5864 /* Initialize sd.vthis2: 5865 * *(e2 + sd.vthis2.offset) = this1; 5866 */ 5867 e2 = el_copytree(e1); 5868 e2 = setEthis(sle.loc, irs, e2, sle.sd, true); 5869 } 5870 /* Initialize sd.vthis: 5871 * *(e1 + sd.vthis.offset) = this; 5872 */ 5873 e1 = setEthis(sle.loc, irs, e1, sle.sd); 5874 5875 e = el_combine(e, e1); 5876 e = el_combine(e, e2); 5877 } 5878 5879 elem *ev = el_var(stmp); 5880 ev.ET = Type_toCtype(sle.sd.type); 5881 e = el_combine(e, ev); 5882 elem_setLoc(e, sle.loc); 5883 return e; 5884 } 5885 5886 /******************************************** 5887 * Append destructors for varsInScope[starti..endi] to er. 5888 * Params: 5889 * irs = context 5890 * er = elem to append destructors to 5891 * starti = starting index in varsInScope[] 5892 * endi = ending index in varsInScope[] 5893 * Returns: 5894 * er with destructors appended 5895 */ 5896 5897 private elem *appendDtors(IRState *irs, elem *er, size_t starti, size_t endi) 5898 { 5899 //printf("appendDtors(%d .. %d)\n", starti, endi); 5900 5901 /* Code gen can be improved by determining if no exceptions can be thrown 5902 * between the OPdctor and OPddtor, and eliminating the OPdctor and OPddtor. 5903 */ 5904 5905 /* Build edtors, an expression that calls destructors on all the variables 5906 * going out of the scope starti..endi 5907 */ 5908 elem *edtors = null; 5909 foreach (i; starti .. endi) 5910 { 5911 elem *ed = (*irs.varsInScope)[i]; 5912 if (ed) // if not skipped 5913 { 5914 //printf("appending dtor\n"); 5915 (*irs.varsInScope)[i] = null; // so these are skipped by outer scopes 5916 edtors = el_combine(ed, edtors); // execute in reverse order 5917 } 5918 } 5919 5920 if (edtors) 5921 { 5922 if (irs.params.isWindows && !irs.params.is64bit) // Win32 5923 { 5924 Blockx *blx = irs.blx; 5925 nteh_declarvars(blx); 5926 } 5927 5928 /* Append edtors to er, while preserving the value of er 5929 */ 5930 if (tybasic(er.Ety) == TYvoid) 5931 { 5932 /* No value to preserve, so simply append 5933 */ 5934 er = el_combine(er, edtors); 5935 } 5936 else 5937 { 5938 elem **pe; 5939 for (pe = &er; (*pe).Eoper == OPcomma; pe = &(*pe).EV.E2) 5940 { 5941 } 5942 elem *erx = *pe; 5943 5944 if (erx.Eoper == OPconst || erx.Eoper == OPrelconst) 5945 { 5946 *pe = el_combine(edtors, erx); 5947 } 5948 else if (elemIsLvalue(erx)) 5949 { 5950 /* Lvalue, take a pointer to it 5951 */ 5952 elem *ep = el_una(OPaddr, TYnptr, erx); 5953 elem *e = el_same(&ep); 5954 ep = el_combine(ep, edtors); 5955 ep = el_combine(ep, e); 5956 e = el_una(OPind, erx.Ety, ep); 5957 e.ET = erx.ET; 5958 *pe = e; 5959 } 5960 else 5961 { 5962 elem *e = el_same(&erx); 5963 erx = el_combine(erx, edtors); 5964 *pe = el_combine(erx, e); 5965 } 5966 } 5967 } 5968 return er; 5969 } 5970 5971 5972 /******************************************* 5973 * Convert Expression to elem, then append destructors for any 5974 * temporaries created in elem. 5975 * Params: 5976 * e = Expression to convert 5977 * irs = context 5978 * Returns: 5979 * generated elem tree 5980 */ 5981 5982 elem *toElemDtor(Expression e, IRState *irs) 5983 { 5984 //printf("Expression.toElemDtor() %s\n", e.toChars()); 5985 5986 /* "may" throw may actually be false if we look at a subset of 5987 * the function. Here, the subset is `e`. If that subset is nothrow, 5988 * we can generate much better code for the destructors for that subset, 5989 * even if the rest of the function throws. 5990 * If mayThrow is false, it cannot be true for some subset of the function, 5991 * so no need to check. 5992 * If calling canThrow() here turns out to be too expensive, 5993 * it can be enabled only for optimized builds. 5994 */ 5995 const mayThrowSave = irs.mayThrow; 5996 if (irs.mayThrow && !canThrow(e, irs.getFunc(), false)) 5997 irs.mayThrow = false; 5998 5999 const starti = irs.varsInScope.dim; 6000 elem* er = toElem(e, irs); 6001 const endi = irs.varsInScope.dim; 6002 6003 irs.mayThrow = mayThrowSave; 6004 6005 // Add destructors 6006 elem* ex = appendDtors(irs, er, starti, endi); 6007 return ex; 6008 } 6009 6010 6011 /******************************************************* 6012 * Write read-only string to object file, create a local symbol for it. 6013 * Makes a copy of str's contents, does not keep a reference to it. 6014 * Params: 6015 * str = string 6016 * len = number of code units in string 6017 * sz = number of bytes per code unit 6018 * Returns: 6019 * Symbol 6020 */ 6021 6022 Symbol *toStringSymbol(const(char)* str, size_t len, size_t sz) 6023 { 6024 //printf("toStringSymbol() %p\n", stringTab); 6025 auto sv = stringTab.update(str, len * sz); 6026 if (!sv.value) 6027 { 6028 Symbol* si; 6029 6030 if (global.params.isWindows) 6031 { 6032 /* This should be in the back end, but mangleToBuffer() is 6033 * in the front end. 6034 */ 6035 /* The stringTab pools common strings within an object file. 6036 * Win32 and Win64 use COMDATs to pool common strings across object files. 6037 */ 6038 import dmd.root.outbuffer : OutBuffer; 6039 import dmd.dmangle; 6040 6041 scope StringExp se = new StringExp(Loc.initial, str[0 .. len], len, cast(ubyte)sz, 'c'); 6042 6043 /* VC++ uses a name mangling scheme, for example, "hello" is mangled to: 6044 * ??_C@_05CJBACGMB@hello?$AA@ 6045 * ^ length 6046 * ^^^^^^^^ 8 byte checksum 6047 * But the checksum algorithm is unknown. Just invent our own. 6048 */ 6049 OutBuffer buf; 6050 buf.writestring("__"); 6051 mangleToBuffer(se, &buf); // recycle how strings are mangled for templates 6052 6053 if (buf.length >= 32 + 2) 6054 { // Replace long string with hash of that string 6055 import dmd.backend.md5; 6056 MD5_CTX mdContext = void; 6057 MD5Init(&mdContext); 6058 MD5Update(&mdContext, cast(ubyte*)buf.peekChars(), cast(uint)buf.length); 6059 MD5Final(&mdContext); 6060 buf.setsize(2); 6061 foreach (u; mdContext.digest) 6062 { 6063 ubyte u1 = u >> 4; 6064 buf.writeByte((u1 < 10) ? u1 + '0' : u1 + 'A' - 10); 6065 u1 = u & 0xF; 6066 buf.writeByte((u1 < 10) ? u1 + '0' : u1 + 'A' - 10); 6067 } 6068 } 6069 6070 si = symbol_calloc(buf.peekChars(), cast(uint)buf.length); 6071 si.Sclass = SCcomdat; 6072 si.Stype = type_static_array(cast(uint)(len * sz), tstypes[TYchar]); 6073 si.Stype.Tcount++; 6074 type_setmangle(&si.Stype, mTYman_c); 6075 si.Sflags |= SFLnodebug | SFLartifical; 6076 si.Sfl = FLdata; 6077 si.Salignment = cast(ubyte)sz; 6078 out_readonly_comdat(si, str, cast(uint)(len * sz), cast(uint)sz); 6079 } 6080 else 6081 { 6082 si = out_string_literal(str, cast(uint)len, cast(uint)sz); 6083 } 6084 6085 sv.value = si; 6086 } 6087 return sv.value; 6088 } 6089 6090 /******************************************************* 6091 * Turn StringExp into Symbol. 6092 */ 6093 6094 Symbol *toStringSymbol(StringExp se) 6095 { 6096 Symbol *si; 6097 const n = cast(int)se.numberOfCodeUnits(); 6098 if (se.sz == 1) 6099 { 6100 const slice = se.peekString(); 6101 si = toStringSymbol(slice.ptr, slice.length, 1); 6102 } 6103 else 6104 { 6105 auto p = cast(char *)mem.xmalloc(n * se.sz); 6106 se.writeTo(p, false); 6107 si = toStringSymbol(p, n, se.sz); 6108 mem.xfree(p); 6109 } 6110 return si; 6111 } 6112 6113 /****************************************************** 6114 * Return an elem that is the file, line, and function suitable 6115 * for insertion into the parameter list. 6116 */ 6117 6118 private elem *filelinefunction(IRState *irs, const ref Loc loc) 6119 { 6120 const(char)* id = loc.filename; 6121 size_t len = strlen(id); 6122 Symbol *si = toStringSymbol(id, len, 1); 6123 elem *efilename = el_pair(TYdarray, el_long(TYsize_t, len), el_ptr(si)); 6124 if (config.exe == EX_WIN64) 6125 efilename = addressElem(efilename, Type.tstring, true); 6126 6127 elem *elinnum = el_long(TYint, loc.linnum); 6128 6129 const(char)* s = ""; 6130 FuncDeclaration fd = irs.getFunc(); 6131 if (fd) 6132 { 6133 s = fd.toPrettyChars(); 6134 } 6135 6136 len = strlen(s); 6137 si = toStringSymbol(s, len, 1); 6138 elem *efunction = el_pair(TYdarray, el_long(TYsize_t, len), el_ptr(si)); 6139 if (config.exe == EX_WIN64) 6140 efunction = addressElem(efunction, Type.tstring, true); 6141 6142 return el_params(efunction, elinnum, efilename, null); 6143 } 6144 6145 /****************************************************** 6146 * Construct elem to run when an array bounds check fails. 6147 * Params: 6148 * irs = to get function from 6149 * loc = to get file/line from 6150 * lwr = lower bound passed, if slice (array[lwr .. upr]). null otherwise. 6151 * upr = upper bound passed if slice (array[lwr .. upr]), index if not a slice (array[upr]) 6152 * elength = length of array 6153 * Returns: 6154 * elem generated 6155 */ 6156 elem *buildArrayBoundsError(IRState *irs, const ref Loc loc, elem* lwr, elem* upr, elem* elength) 6157 { 6158 if (irs.params.checkAction == CHECKACTION.C) 6159 { 6160 return callCAssert(irs, loc, null, null, "array overflow"); 6161 } 6162 if (irs.params.checkAction == CHECKACTION.halt) 6163 { 6164 return genHalt(loc); 6165 } 6166 auto eassert = el_var(getRtlsym(RTLSYM_DARRAYP)); 6167 auto efile = toEfilenamePtr(cast(Module)irs.blx._module); 6168 auto eline = el_long(TYint, loc.linnum); 6169 if(upr is null) 6170 { 6171 upr = el_long(TYsize_t, 0); 6172 } 6173 if(lwr is null) 6174 { 6175 lwr = el_long(TYsize_t, 0); 6176 } 6177 if(elength is null) 6178 { 6179 elength = el_long(TYsize_t, 0); 6180 } 6181 return el_bin(OPcall, TYvoid, eassert, el_params(elength, upr, lwr, eline, efile, null)); 6182 } 6183 6184 /****************************************************** 6185 * Replace call to GC allocator with call to tracing GC allocator. 6186 * Params: 6187 * irs = to get function from 6188 * e = elem to modify in place 6189 * loc = to get file/line from 6190 */ 6191 6192 void toTraceGC(IRState *irs, elem *e, const ref Loc loc) 6193 { 6194 static immutable int[2][25] map = 6195 [ 6196 [ RTLSYM_NEWCLASS, RTLSYM_TRACENEWCLASS ], 6197 [ RTLSYM_NEWITEMT, RTLSYM_TRACENEWITEMT ], 6198 [ RTLSYM_NEWITEMIT, RTLSYM_TRACENEWITEMIT ], 6199 [ RTLSYM_NEWARRAYT, RTLSYM_TRACENEWARRAYT ], 6200 [ RTLSYM_NEWARRAYIT, RTLSYM_TRACENEWARRAYIT ], 6201 [ RTLSYM_NEWARRAYMTX, RTLSYM_TRACENEWARRAYMTX ], 6202 [ RTLSYM_NEWARRAYMITX, RTLSYM_TRACENEWARRAYMITX ], 6203 6204 [ RTLSYM_DELCLASS, RTLSYM_TRACEDELCLASS ], 6205 [ RTLSYM_CALLFINALIZER, RTLSYM_TRACECALLFINALIZER ], 6206 [ RTLSYM_CALLINTERFACEFINALIZER, RTLSYM_TRACECALLINTERFACEFINALIZER ], 6207 [ RTLSYM_DELINTERFACE, RTLSYM_TRACEDELINTERFACE ], 6208 [ RTLSYM_DELARRAYT, RTLSYM_TRACEDELARRAYT ], 6209 [ RTLSYM_DELMEMORY, RTLSYM_TRACEDELMEMORY ], 6210 [ RTLSYM_DELSTRUCT, RTLSYM_TRACEDELSTRUCT ], 6211 6212 [ RTLSYM_ARRAYLITERALTX, RTLSYM_TRACEARRAYLITERALTX ], 6213 [ RTLSYM_ASSOCARRAYLITERALTX, RTLSYM_TRACEASSOCARRAYLITERALTX ], 6214 6215 [ RTLSYM_ARRAYCATT, RTLSYM_TRACEARRAYCATT ], 6216 [ RTLSYM_ARRAYCATNTX, RTLSYM_TRACEARRAYCATNTX ], 6217 6218 [ RTLSYM_ARRAYAPPENDCD, RTLSYM_TRACEARRAYAPPENDCD ], 6219 [ RTLSYM_ARRAYAPPENDWD, RTLSYM_TRACEARRAYAPPENDWD ], 6220 [ RTLSYM_ARRAYAPPENDT, RTLSYM_TRACEARRAYAPPENDT ], 6221 [ RTLSYM_ARRAYAPPENDCTX, RTLSYM_TRACEARRAYAPPENDCTX ], 6222 6223 [ RTLSYM_ARRAYSETLENGTHT, RTLSYM_TRACEARRAYSETLENGTHT ], 6224 [ RTLSYM_ARRAYSETLENGTHIT, RTLSYM_TRACEARRAYSETLENGTHIT ], 6225 6226 [ RTLSYM_ALLOCMEMORY, RTLSYM_TRACEALLOCMEMORY ], 6227 ]; 6228 6229 if (irs.params.tracegc && loc.filename) 6230 { 6231 assert(e.Eoper == OPcall); 6232 elem *e1 = e.EV.E1; 6233 assert(e1.Eoper == OPvar); 6234 6235 auto s = e1.EV.Vsym; 6236 /* In -dip1008 code the allocation of exceptions is no longer done by the 6237 * gc, but by a manual reference counting mechanism implementend in druntime. 6238 * If that is the case, then there is nothing to trace. 6239 */ 6240 if (s == getRtlsym(RTLSYM_NEWTHROW)) 6241 return; 6242 foreach (ref m; map) 6243 { 6244 if (s == getRtlsym(m[0])) 6245 { 6246 e1.EV.Vsym = getRtlsym(m[1]); 6247 e.EV.E2 = el_param(e.EV.E2, filelinefunction(irs, loc)); 6248 return; 6249 } 6250 } 6251 assert(0); 6252 } 6253 } 6254 6255 6256 /**************************************** 6257 * Generate call to C's assert failure function. 6258 * One of exp, emsg, or str must not be null. 6259 * Params: 6260 * irs = context 6261 * loc = location to use for assert message 6262 * exp = if not null expression to test (not evaluated, but converted to a string) 6263 * emsg = if not null then informative message to be computed at run time 6264 * str = if not null then informative message string 6265 * Returns: 6266 * generated call 6267 */ 6268 elem *callCAssert(IRState *irs, const ref Loc loc, Expression exp, Expression emsg, const(char)* str) 6269 { 6270 //printf("callCAssert.toElem() %s\n", e.toChars()); 6271 Module m = cast(Module)irs.blx._module; 6272 const(char)* mname = m.srcfile.toChars(); 6273 6274 elem* getFuncName() 6275 { 6276 const(char)* id = ""; 6277 FuncDeclaration fd = irs.getFunc(); 6278 if (fd) 6279 id = fd.toPrettyChars(); 6280 const len = strlen(id); 6281 Symbol *si = toStringSymbol(id, len, 1); 6282 return el_ptr(si); 6283 } 6284 6285 //printf("filename = '%s'\n", loc.filename); 6286 //printf("module = '%s'\n", mname); 6287 6288 /* If the source file name has changed, probably due 6289 * to a #line directive. 6290 */ 6291 elem *efilename; 6292 if (loc.filename && strcmp(loc.filename, mname) != 0) 6293 { 6294 const(char)* id = loc.filename; 6295 size_t len = strlen(id); 6296 Symbol *si = toStringSymbol(id, len, 1); 6297 efilename = el_ptr(si); 6298 } 6299 else 6300 { 6301 efilename = toEfilenamePtr(m); 6302 } 6303 6304 elem *elmsg; 6305 if (emsg) 6306 { 6307 // Assuming here that emsg generates a 0 terminated string 6308 auto e = toElemDtor(emsg, irs); 6309 elmsg = array_toPtr(Type.tvoid.arrayOf(), e); 6310 } 6311 else if (exp) 6312 { 6313 // Generate a message out of the assert expression 6314 const(char)* id = exp.toChars(); 6315 const len = strlen(id); 6316 Symbol *si = toStringSymbol(id, len, 1); 6317 elmsg = el_ptr(si); 6318 } 6319 else 6320 { 6321 assert(str); 6322 const len = strlen(str); 6323 Symbol *si = toStringSymbol(str, len, 1); 6324 elmsg = el_ptr(si); 6325 } 6326 6327 auto eline = el_long(TYint, loc.linnum); 6328 6329 elem *ea; 6330 if (irs.params.isOSX) 6331 { 6332 // __assert_rtn(func, file, line, msg); 6333 elem* efunc = getFuncName(); 6334 auto eassert = el_var(getRtlsym(RTLSYM_C__ASSERT_RTN)); 6335 ea = el_bin(OPcall, TYvoid, eassert, el_params(elmsg, eline, efilename, efunc, null)); 6336 } 6337 else 6338 { 6339 version (CRuntime_Musl) 6340 { 6341 // __assert_fail(exp, file, line, func); 6342 elem* efunc = getFuncName(); 6343 auto eassert = el_var(getRtlsym(RTLSYM_C__ASSERT_FAIL)); 6344 ea = el_bin(OPcall, TYvoid, eassert, el_params(elmsg, efilename, eline, efunc, null)); 6345 } 6346 else 6347 { 6348 // [_]_assert(msg, file, line); 6349 const rtlsym = (irs.params.isWindows) ? RTLSYM_C_ASSERT : RTLSYM_C__ASSERT; 6350 auto eassert = el_var(getRtlsym(rtlsym)); 6351 ea = el_bin(OPcall, TYvoid, eassert, el_params(eline, efilename, elmsg, null)); 6352 } 6353 } 6354 return ea; 6355 } 6356 6357 /******************************************** 6358 * Generate HALT instruction. 6359 * Params: 6360 * loc = location to use for debug info 6361 * Returns: 6362 * generated instruction 6363 */ 6364 elem *genHalt(const ref Loc loc) 6365 { 6366 elem *e = el_calloc(); 6367 e.Ety = TYvoid; 6368 e.Eoper = OPhalt; 6369 elem_setLoc(e, loc); 6370 return e; 6371 } 6372 6373 /************************************************* 6374 * Determine if zero bits need to be copied for this backend type 6375 * Params: 6376 * t = backend type 6377 * Returns: 6378 * true if 0 bits 6379 */ 6380 bool type_zeroCopy(type* t) 6381 { 6382 return type_size(t) == 0 || 6383 (tybasic(t.Tty) == TYstruct && 6384 (t.Ttag.Stype.Ttag.Sstruct.Sflags & STR0size)); 6385 } 6386 6387 /************************************************** 6388 * Generate a copy from e2 to e1. 6389 * Params: 6390 * e1 = lvalue 6391 * e2 = rvalue 6392 * t = value type 6393 * tx = if !null, then t converted to C type 6394 * Returns: 6395 * generated elem 6396 */ 6397 elem* elAssign(elem* e1, elem* e2, Type t, type* tx) 6398 { 6399 elem *e = el_bin(OPeq, e2.Ety, e1, e2); 6400 switch (tybasic(e2.Ety)) 6401 { 6402 case TYarray: 6403 e.Ejty = e.Ety = TYstruct; 6404 goto case TYstruct; 6405 6406 case TYstruct: 6407 e.Eoper = OPstreq; 6408 if (!tx) 6409 tx = Type_toCtype(t); 6410 e.ET = tx; 6411 // if (type_zeroCopy(tx)) 6412 // e.Eoper = OPcomma; 6413 break; 6414 6415 default: 6416 break; 6417 } 6418 return e; 6419 } 6420 6421 /************************************************** 6422 * Initialize the dual-context array with the context pointers. 6423 * Params: 6424 * loc = line and file of what line to show usage for 6425 * irs = current context to get the second context from 6426 * fd = the target function 6427 * ethis2 = dual-context array 6428 * ethis = the first context 6429 * eside = where to store the assignment expressions 6430 * Returns: 6431 * `ethis2` if successful, null otherwise 6432 */ 6433 elem* setEthis2(const ref Loc loc, IRState* irs, FuncDeclaration fd, elem* ethis2, elem** ethis, elem** eside) 6434 { 6435 if (!fd.isThis2) 6436 return null; 6437 6438 assert(ethis2 && ethis && *ethis); 6439 6440 elem* ectx0 = el_una(OPind, (*ethis).Ety, el_copytree(ethis2)); 6441 elem* eeq0 = el_bin(OPeq, (*ethis).Ety, ectx0, *ethis); 6442 *ethis = el_copytree(ectx0); 6443 *eside = el_combine(eeq0, *eside); 6444 6445 elem* ethis1 = getEthis(loc, irs, fd, fd.toParent2()); 6446 elem* ectx1 = el_bin(OPadd, TYnptr, el_copytree(ethis2), el_long(TYsize_t, tysize(TYnptr))); 6447 ectx1 = el_una(OPind, TYnptr, ectx1); 6448 elem* eeq1 = el_bin(OPeq, ethis1.Ety, ectx1, ethis1); 6449 *eside = el_combine(eeq1, *eside); 6450 6451 return ethis2; 6452 }