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