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