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