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