1 1.1 mrg /** 2 1.1 mrg * Perform constant folding. 3 1.1 mrg * 4 1.1 mrg * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved 5 1.1 mrg * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 1.1 mrg * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 1.1 mrg * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/optimize.d, _optimize.d) 8 1.1 mrg * Documentation: https://dlang.org/phobos/dmd_optimize.html 9 1.1 mrg * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/optimize.d 10 1.1 mrg */ 11 1.1 mrg 12 1.1 mrg module dmd.optimize; 13 1.1 mrg 14 1.1 mrg import core.stdc.stdio; 15 1.1 mrg 16 1.1 mrg import dmd.astenums; 17 1.1 mrg import dmd.constfold; 18 1.1 mrg import dmd.ctfeexpr; 19 1.1 mrg import dmd.dclass; 20 1.1 mrg import dmd.declaration; 21 1.1 mrg import dmd.dsymbol; 22 1.1 mrg import dmd.dsymbolsem; 23 1.1 mrg import dmd.errors; 24 1.1 mrg import dmd.expression; 25 1.1 mrg import dmd.expressionsem; 26 1.1 mrg import dmd.globals; 27 1.1 mrg import dmd.init; 28 1.1 mrg import dmd.mtype; 29 1.1 mrg import dmd.printast; 30 1.1 mrg import dmd.root.ctfloat; 31 1.1 mrg import dmd.sideeffect; 32 1.1 mrg import dmd.tokens; 33 1.1 mrg import dmd.visitor; 34 1.1 mrg 35 1.1 mrg /************************************* 36 1.1 mrg * If variable has a const initializer, 37 1.1 mrg * return that initializer. 38 1.1 mrg * Returns: 39 1.1 mrg * initializer if there is one, 40 1.1 mrg * null if not, 41 1.1 mrg * ErrorExp if error 42 1.1 mrg */ 43 1.1 mrg Expression expandVar(int result, VarDeclaration v) 44 1.1 mrg { 45 1.1 mrg //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v.toChars() : "null"); 46 1.1 mrg 47 1.1 mrg /******** 48 1.1 mrg * Params: 49 1.1 mrg * e = initializer expression 50 1.1 mrg */ 51 1.1 mrg Expression initializerReturn(Expression e) 52 1.1 mrg { 53 1.1 mrg if (e.type != v.type) 54 1.1 mrg { 55 1.1 mrg e = e.castTo(null, v.type); 56 1.1 mrg } 57 1.1 mrg v.inuse++; 58 1.1 mrg e = e.optimize(result); 59 1.1 mrg v.inuse--; 60 1.1 mrg //if (e) printf("\te = %p, %s, e.type = %d, %s\n", e, e.toChars(), e.type.ty, e.type.toChars()); 61 1.1 mrg return e; 62 1.1 mrg } 63 1.1 mrg 64 1.1 mrg static Expression nullReturn() 65 1.1 mrg { 66 1.1 mrg return null; 67 1.1 mrg } 68 1.1 mrg 69 1.1 mrg static Expression errorReturn() 70 1.1 mrg { 71 1.1 mrg return ErrorExp.get(); 72 1.1 mrg } 73 1.1 mrg 74 1.1 mrg if (!v) 75 1.1 mrg return nullReturn(); 76 1.1 mrg if (!v.originalType && v.semanticRun < PASS.semanticdone) // semantic() not yet run 77 1.1 mrg v.dsymbolSemantic(null); 78 1.1 mrg if (v.type && 79 1.1 mrg (v.isConst() || v.isImmutable() || v.storage_class & STC.manifest)) 80 1.1 mrg { 81 1.1 mrg Type tb = v.type.toBasetype(); 82 1.1 mrg if (v.storage_class & STC.manifest || 83 1.1 mrg tb.isscalar() || 84 1.1 mrg ((result & WANTexpand) && (tb.ty != Tsarray && tb.ty != Tstruct))) 85 1.1 mrg { 86 1.1 mrg if (v._init) 87 1.1 mrg { 88 1.1 mrg if (v.inuse) 89 1.1 mrg { 90 1.1 mrg if (v.storage_class & STC.manifest) 91 1.1 mrg { 92 1.1 mrg v.error("recursive initialization of constant"); 93 1.1 mrg return errorReturn(); 94 1.1 mrg } 95 1.1 mrg return nullReturn(); 96 1.1 mrg } 97 1.1 mrg Expression ei = v.getConstInitializer(); 98 1.1 mrg if (!ei) 99 1.1 mrg { 100 1.1 mrg if (v.storage_class & STC.manifest) 101 1.1 mrg { 102 1.1 mrg v.error("enum cannot be initialized with `%s`", v._init.toChars()); 103 1.1 mrg return errorReturn(); 104 1.1 mrg } 105 1.1 mrg return nullReturn(); 106 1.1 mrg } 107 1.1 mrg if (ei.op == EXP.construct || ei.op == EXP.blit) 108 1.1 mrg { 109 1.1 mrg AssignExp ae = cast(AssignExp)ei; 110 1.1 mrg ei = ae.e2; 111 1.1 mrg if (ei.isConst() == 1) 112 1.1 mrg { 113 1.1 mrg } 114 1.1 mrg else if (ei.op == EXP.string_) 115 1.1 mrg { 116 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=14459 117 1.1 mrg // Do not constfold the string literal 118 1.1 mrg // if it's typed as a C string, because the value expansion 119 1.1 mrg // will drop the pointer identity. 120 1.1 mrg if (!(result & WANTexpand) && ei.type.toBasetype().ty == Tpointer) 121 1.1 mrg return nullReturn(); 122 1.1 mrg } 123 1.1 mrg else 124 1.1 mrg return nullReturn(); 125 1.1 mrg if (ei.type == v.type) 126 1.1 mrg { 127 1.1 mrg // const variable initialized with const expression 128 1.1 mrg } 129 1.1 mrg else if (ei.implicitConvTo(v.type) >= MATCH.constant) 130 1.1 mrg { 131 1.1 mrg // const var initialized with non-const expression 132 1.1 mrg ei = ei.implicitCastTo(null, v.type); 133 1.1 mrg ei = ei.expressionSemantic(null); 134 1.1 mrg } 135 1.1 mrg else 136 1.1 mrg return nullReturn(); 137 1.1 mrg } 138 1.1 mrg else if (!(v.storage_class & STC.manifest) && 139 1.1 mrg ei.isConst() != 1 && 140 1.1 mrg ei.op != EXP.string_ && 141 1.1 mrg ei.op != EXP.address) 142 1.1 mrg { 143 1.1 mrg return nullReturn(); 144 1.1 mrg } 145 1.1 mrg 146 1.1 mrg if (!ei.type) 147 1.1 mrg { 148 1.1 mrg return nullReturn(); 149 1.1 mrg } 150 1.1 mrg else 151 1.1 mrg { 152 1.1 mrg // Should remove the copy() operation by 153 1.1 mrg // making all mods to expressions copy-on-write 154 1.1 mrg return initializerReturn(ei.copy()); 155 1.1 mrg } 156 1.1 mrg } 157 1.1 mrg else 158 1.1 mrg { 159 1.1 mrg // v does not have an initializer 160 1.1 mrg version (all) 161 1.1 mrg { 162 1.1 mrg return nullReturn(); 163 1.1 mrg } 164 1.1 mrg else 165 1.1 mrg { 166 1.1 mrg // BUG: what if const is initialized in constructor? 167 1.1 mrg auto e = v.type.defaultInit(); 168 1.1 mrg e.loc = e1.loc; 169 1.1 mrg return initializerReturn(e); 170 1.1 mrg } 171 1.1 mrg } 172 1.1 mrg assert(0); 173 1.1 mrg } 174 1.1 mrg } 175 1.1 mrg return nullReturn(); 176 1.1 mrg } 177 1.1 mrg 178 1.1 mrg private Expression fromConstInitializer(int result, Expression e1) 179 1.1 mrg { 180 1.1 mrg //printf("fromConstInitializer(result = %x, %s)\n", result, e1.toChars()); 181 1.1 mrg //static int xx; if (xx++ == 10) assert(0); 182 1.1 mrg Expression e = e1; 183 1.1 mrg if (auto ve = e1.isVarExp()) 184 1.1 mrg { 185 1.1 mrg VarDeclaration v = ve.var.isVarDeclaration(); 186 1.1 mrg e = expandVar(result, v); 187 1.1 mrg if (e) 188 1.1 mrg { 189 1.1 mrg // If it is a comma expression involving a declaration, we mustn't 190 1.1 mrg // perform a copy -- we'd get two declarations of the same variable. 191 1.1 mrg // See bugzilla 4465. 192 1.1 mrg if (e.op == EXP.comma && e.isCommaExp().e1.isDeclarationExp()) 193 1.1 mrg e = e1; 194 1.1 mrg else if (e.type != e1.type && e1.type && e1.type.ty != Tident) 195 1.1 mrg { 196 1.1 mrg // Type 'paint' operation 197 1.1 mrg e = e.copy(); 198 1.1 mrg e.type = e1.type; 199 1.1 mrg } 200 1.1 mrg e.loc = e1.loc; 201 1.1 mrg } 202 1.1 mrg else 203 1.1 mrg { 204 1.1 mrg e = e1; 205 1.1 mrg } 206 1.1 mrg } 207 1.1 mrg return e; 208 1.1 mrg } 209 1.1 mrg 210 1.1 mrg /*** 211 1.1 mrg * It is possible for constant folding to change an array expression of 212 1.1 mrg * unknown length, into one where the length is known. 213 1.1 mrg * If the expression 'arr' is a literal, set lengthVar to be its length. 214 1.1 mrg * Params: 215 1.1 mrg * lengthVar = variable declaration for the `.length` property 216 1.1 mrg * arr = String, ArrayLiteral, or of TypeSArray 217 1.1 mrg */ 218 1.1 mrg package void setLengthVarIfKnown(VarDeclaration lengthVar, Expression arr) 219 1.1 mrg { 220 1.1 mrg if (!lengthVar) 221 1.1 mrg return; 222 1.1 mrg if (lengthVar._init && !lengthVar._init.isVoidInitializer()) 223 1.1 mrg return; // we have previously calculated the length 224 1.1 mrg dinteger_t len; 225 1.1 mrg if (auto se = arr.isStringExp()) 226 1.1 mrg len = se.len; 227 1.1 mrg else if (auto ale = arr.isArrayLiteralExp()) 228 1.1 mrg len = ale.elements.dim; 229 1.1 mrg else 230 1.1 mrg { 231 1.1 mrg auto tsa = arr.type.toBasetype().isTypeSArray(); 232 1.1 mrg if (!tsa) 233 1.1 mrg return; // we don't know the length yet 234 1.1 mrg len = tsa.dim.toInteger(); 235 1.1 mrg } 236 1.1 mrg Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t); 237 1.1 mrg lengthVar._init = new ExpInitializer(Loc.initial, dollar); 238 1.1 mrg lengthVar.storage_class |= STC.static_ | STC.const_; 239 1.1 mrg } 240 1.1 mrg 241 1.1 mrg /*** 242 1.1 mrg * Same as above, but determines the length from 'type'. 243 1.1 mrg * Params: 244 1.1 mrg * lengthVar = variable declaration for the `.length` property 245 1.1 mrg * type = TypeSArray 246 1.1 mrg */ 247 1.1 mrg package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type) 248 1.1 mrg { 249 1.1 mrg if (!lengthVar) 250 1.1 mrg return; 251 1.1 mrg if (lengthVar._init && !lengthVar._init.isVoidInitializer()) 252 1.1 mrg return; // we have previously calculated the length 253 1.1 mrg auto tsa = type.toBasetype().isTypeSArray(); 254 1.1 mrg if (!tsa) 255 1.1 mrg return; // we don't know the length yet 256 1.1 mrg const len = tsa.dim.toInteger(); 257 1.1 mrg Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t); 258 1.1 mrg lengthVar._init = new ExpInitializer(Loc.initial, dollar); 259 1.1 mrg lengthVar.storage_class |= STC.static_ | STC.const_; 260 1.1 mrg } 261 1.1 mrg 262 1.1 mrg /********************************* 263 1.1 mrg * Constant fold an Expression. 264 1.1 mrg * Params: 265 1.1 mrg * e = expression to const fold; this may get modified in-place 266 1.1 mrg * result = WANTvalue, WANTexpand, or both 267 1.1 mrg * keepLvalue = `e` is an lvalue, and keep it as an lvalue since it is 268 1.1 mrg * an argument to a `ref` or `out` parameter, or the operand of `&` operator 269 1.1 mrg * Returns: 270 1.1 mrg * Constant folded version of `e` 271 1.1 mrg */ 272 1.1 mrg Expression Expression_optimize(Expression e, int result, bool keepLvalue) 273 1.1 mrg { 274 1.1 mrg //printf("Expression_optimize() e: %s result: %d keepLvalue %d\n", e.toChars(), result, keepLvalue); 275 1.1 mrg Expression ret = e; 276 1.1 mrg 277 1.1 mrg void error() 278 1.1 mrg { 279 1.1 mrg ret = ErrorExp.get(); 280 1.1 mrg } 281 1.1 mrg 282 1.1 mrg /* Returns: true if error 283 1.1 mrg */ 284 1.1 mrg bool expOptimize(ref Expression e, int flags, bool keepLvalue = false) 285 1.1 mrg { 286 1.1 mrg if (!e) 287 1.1 mrg return false; 288 1.1 mrg Expression ex = Expression_optimize(e, flags, keepLvalue); 289 1.1 mrg if (ex.op == EXP.error) 290 1.1 mrg { 291 1.1 mrg ret = ex; // store error result 292 1.1 mrg return true; 293 1.1 mrg } 294 1.1 mrg else 295 1.1 mrg { 296 1.1 mrg e = ex; // modify original 297 1.1 mrg return false; 298 1.1 mrg } 299 1.1 mrg } 300 1.1 mrg 301 1.1 mrg bool unaOptimize(UnaExp e, int flags) 302 1.1 mrg { 303 1.1 mrg return expOptimize(e.e1, flags); 304 1.1 mrg } 305 1.1 mrg 306 1.1 mrg bool binOptimize(BinExp e, int flags, bool keepLhsLvalue = false) 307 1.1 mrg { 308 1.1 mrg return expOptimize(e.e1, flags, keepLhsLvalue) | 309 1.1 mrg expOptimize(e.e2, flags); 310 1.1 mrg } 311 1.1 mrg 312 1.1 mrg void visitExp(Expression e) 313 1.1 mrg { 314 1.1 mrg //printf("Expression::optimize(result = x%x) %s\n", result, e.toChars()); 315 1.1 mrg } 316 1.1 mrg 317 1.1 mrg void visitVar(VarExp e) 318 1.1 mrg { 319 1.1 mrg VarDeclaration v = e.var.isVarDeclaration(); 320 1.1 mrg 321 1.1 mrg if (!(keepLvalue && v && !(v.storage_class & STC.manifest))) 322 1.1 mrg ret = fromConstInitializer(result, e); 323 1.1 mrg 324 1.1 mrg // if unoptimized, try to optimize the dtor expression 325 1.1 mrg // (e.g., might be a LogicalExp with constant lhs) 326 1.1 mrg if (ret == e && v && v.edtor) 327 1.1 mrg { 328 1.1 mrg // prevent infinite recursion (`<var>.~this()`) 329 1.1 mrg if (!v.inuse) 330 1.1 mrg { 331 1.1 mrg v.inuse++; 332 1.1 mrg expOptimize(v.edtor, WANTvalue); 333 1.1 mrg v.inuse--; 334 1.1 mrg } 335 1.1 mrg } 336 1.1 mrg } 337 1.1 mrg 338 1.1 mrg void visitTuple(TupleExp e) 339 1.1 mrg { 340 1.1 mrg expOptimize(e.e0, WANTvalue); 341 1.1 mrg foreach (ref ex; (*e.exps)[]) 342 1.1 mrg { 343 1.1 mrg expOptimize(ex, WANTvalue); 344 1.1 mrg } 345 1.1 mrg } 346 1.1 mrg 347 1.1 mrg void visitArrayLiteral(ArrayLiteralExp e) 348 1.1 mrg { 349 1.1 mrg if (e.elements) 350 1.1 mrg { 351 1.1 mrg expOptimize(e.basis, result & WANTexpand); 352 1.1 mrg foreach (ref ex; (*e.elements)[]) 353 1.1 mrg { 354 1.1 mrg expOptimize(ex, result & WANTexpand); 355 1.1 mrg } 356 1.1 mrg } 357 1.1 mrg } 358 1.1 mrg 359 1.1 mrg void visitAssocArrayLiteral(AssocArrayLiteralExp e) 360 1.1 mrg { 361 1.1 mrg assert(e.keys.dim == e.values.dim); 362 1.1 mrg foreach (i, ref ekey; (*e.keys)[]) 363 1.1 mrg { 364 1.1 mrg expOptimize(ekey, result & WANTexpand); 365 1.1 mrg expOptimize((*e.values)[i], result & WANTexpand); 366 1.1 mrg } 367 1.1 mrg } 368 1.1 mrg 369 1.1 mrg void visitStructLiteral(StructLiteralExp e) 370 1.1 mrg { 371 1.1 mrg if (e.stageflags & stageOptimize) 372 1.1 mrg return; 373 1.1 mrg int old = e.stageflags; 374 1.1 mrg e.stageflags |= stageOptimize; 375 1.1 mrg if (e.elements) 376 1.1 mrg { 377 1.1 mrg foreach (ref ex; (*e.elements)[]) 378 1.1 mrg { 379 1.1 mrg expOptimize(ex, result & WANTexpand); 380 1.1 mrg } 381 1.1 mrg } 382 1.1 mrg e.stageflags = old; 383 1.1 mrg } 384 1.1 mrg 385 1.1 mrg void visitUna(UnaExp e) 386 1.1 mrg { 387 1.1 mrg //printf("UnaExp::optimize() %s\n", e.toChars()); 388 1.1 mrg if (unaOptimize(e, result)) 389 1.1 mrg return; 390 1.1 mrg } 391 1.1 mrg 392 1.1 mrg void visitNeg(NegExp e) 393 1.1 mrg { 394 1.1 mrg if (unaOptimize(e, result)) 395 1.1 mrg return; 396 1.1 mrg if (e.e1.isConst() == 1) 397 1.1 mrg { 398 1.1 mrg ret = Neg(e.type, e.e1).copy(); 399 1.1 mrg } 400 1.1 mrg } 401 1.1 mrg 402 1.1 mrg void visitCom(ComExp e) 403 1.1 mrg { 404 1.1 mrg if (unaOptimize(e, result)) 405 1.1 mrg return; 406 1.1 mrg if (e.e1.isConst() == 1) 407 1.1 mrg { 408 1.1 mrg ret = Com(e.type, e.e1).copy(); 409 1.1 mrg } 410 1.1 mrg } 411 1.1 mrg 412 1.1 mrg void visitNop(NotExp e) 413 1.1 mrg { 414 1.1 mrg if (unaOptimize(e, result)) 415 1.1 mrg return; 416 1.1 mrg if (e.e1.isConst() == 1) 417 1.1 mrg { 418 1.1 mrg ret = Not(e.type, e.e1).copy(); 419 1.1 mrg } 420 1.1 mrg } 421 1.1 mrg 422 1.1 mrg void visitSymOff(SymOffExp e) 423 1.1 mrg { 424 1.1 mrg assert(e.var); 425 1.1 mrg } 426 1.1 mrg 427 1.1 mrg void visitAddr(AddrExp e) 428 1.1 mrg { 429 1.1 mrg //printf("AddrExp::optimize(result = %d, keepLvalue = %d) %s\n", result, keepLvalue, e.toChars()); 430 1.1 mrg /* Rewrite &(a,b) as (a,&b) 431 1.1 mrg */ 432 1.1 mrg if (auto ce = e.e1.isCommaExp()) 433 1.1 mrg { 434 1.1 mrg auto ae = new AddrExp(e.loc, ce.e2, e.type); 435 1.1 mrg ret = new CommaExp(ce.loc, ce.e1, ae); 436 1.1 mrg ret.type = e.type; 437 1.1 mrg return; 438 1.1 mrg } 439 1.1 mrg // Keep lvalue-ness 440 1.1 mrg if (expOptimize(e.e1, result, true)) 441 1.1 mrg return; // error return 442 1.1 mrg 443 1.1 mrg // Convert &*ex to ex 444 1.1 mrg if (auto pe = e.e1.isPtrExp()) 445 1.1 mrg { 446 1.1 mrg Expression ex = pe.e1; 447 1.1 mrg if (e.type.equals(ex.type)) 448 1.1 mrg ret = ex; 449 1.1 mrg else if (e.type.toBasetype().equivalent(ex.type.toBasetype())) 450 1.1 mrg { 451 1.1 mrg ret = ex.copy(); 452 1.1 mrg ret.type = e.type; 453 1.1 mrg } 454 1.1 mrg return; 455 1.1 mrg } 456 1.1 mrg if (auto ve = e.e1.isVarExp()) 457 1.1 mrg { 458 1.1 mrg if (!ve.var.isReference() && !ve.var.isImportedSymbol()) 459 1.1 mrg { 460 1.1 mrg ret = new SymOffExp(e.loc, ve.var, 0, ve.hasOverloads); 461 1.1 mrg ret.type = e.type; 462 1.1 mrg return; 463 1.1 mrg } 464 1.1 mrg } 465 1.1 mrg if (e.e1.isDotVarExp()) 466 1.1 mrg { 467 1.1 mrg /****************************** 468 1.1 mrg * Run down the left side of the a.b.c expression to determine the 469 1.1 mrg * leftmost variable being addressed (`a`), and accumulate the offsets of the `.b` and `.c`. 470 1.1 mrg * Params: 471 1.1 mrg * e = the DotVarExp or VarExp 472 1.1 mrg * var = set to the VarExp at the end, or null if doesn't end in VarExp 473 1.1 mrg * eint = set to the IntegerExp at the end, or null if doesn't end in IntegerExp 474 1.1 mrg * offset = accumulation of all the .var offsets encountered 475 1.1 mrg * Returns: true on error 476 1.1 mrg */ 477 1.1 mrg static bool getVarAndOffset(Expression e, out VarDeclaration var, out IntegerExp eint, ref uint offset) 478 1.1 mrg { 479 1.1 mrg if (e.type.size() == SIZE_INVALID) // trigger computation of v.offset 480 1.1 mrg return true; 481 1.1 mrg 482 1.1 mrg if (auto dve = e.isDotVarExp()) 483 1.1 mrg { 484 1.1 mrg auto v = dve.var.isVarDeclaration(); 485 1.1 mrg if (!v || !v.isField() || v.isBitFieldDeclaration()) 486 1.1 mrg return false; 487 1.1 mrg 488 1.1 mrg if (getVarAndOffset(dve.e1, var, eint, offset)) 489 1.1 mrg return true; 490 1.1 mrg offset += v.offset; 491 1.1 mrg } 492 1.1 mrg else if (auto ve = e.isVarExp()) 493 1.1 mrg { 494 1.1 mrg if (!ve.var.isReference() && 495 1.1 mrg !ve.var.isImportedSymbol() && 496 1.1 mrg ve.var.isDataseg() && 497 1.1 mrg ve.var.isCsymbol()) 498 1.1 mrg { 499 1.1 mrg var = ve.var.isVarDeclaration(); 500 1.1 mrg } 501 1.1 mrg } 502 1.1 mrg else if (auto ep = e.isPtrExp()) 503 1.1 mrg { 504 1.1 mrg if (auto ei = ep.e1.isIntegerExp()) 505 1.1 mrg { 506 1.1 mrg eint = ei; 507 1.1 mrg } 508 1.1 mrg else if (auto se = ep.e1.isSymOffExp()) 509 1.1 mrg { 510 1.1 mrg if (!se.var.isReference() && 511 1.1 mrg !se.var.isImportedSymbol() && 512 1.1 mrg se.var.isDataseg()) 513 1.1 mrg { 514 1.1 mrg var = se.var.isVarDeclaration(); 515 1.1 mrg offset += se.offset; 516 1.1 mrg } 517 1.1 mrg } 518 1.1 mrg } 519 1.1 mrg else if (auto ei = e.isIndexExp()) 520 1.1 mrg { 521 1.1 mrg if (auto ve = ei.e1.isVarExp()) 522 1.1 mrg { 523 1.1 mrg if (!ve.var.isReference() && 524 1.1 mrg !ve.var.isImportedSymbol() && 525 1.1 mrg ve.var.isDataseg() && 526 1.1 mrg ve.var.isCsymbol()) 527 1.1 mrg { 528 1.1 mrg if (auto ie = ei.e2.isIntegerExp()) 529 1.1 mrg { 530 1.1 mrg var = ve.var.isVarDeclaration(); 531 1.1 mrg offset += ie.toInteger() * ve.type.toBasetype().nextOf().size(); 532 1.1 mrg } 533 1.1 mrg } 534 1.1 mrg } 535 1.1 mrg } 536 1.1 mrg return false; 537 1.1 mrg } 538 1.1 mrg 539 1.1 mrg uint offset; 540 1.1 mrg VarDeclaration var; 541 1.1 mrg IntegerExp eint; 542 1.1 mrg if (getVarAndOffset(e.e1, var, eint, offset)) 543 1.1 mrg { 544 1.1 mrg ret = ErrorExp.get(); 545 1.1 mrg return; 546 1.1 mrg } 547 1.1 mrg if (var) 548 1.1 mrg { 549 1.1 mrg ret = new SymOffExp(e.loc, var, offset, false); 550 1.1 mrg ret.type = e.type; 551 1.1 mrg return; 552 1.1 mrg } 553 1.1 mrg if (eint) 554 1.1 mrg { 555 1.1 mrg ret = new IntegerExp(e.loc, eint.toInteger() + offset, e.type); 556 1.1 mrg return; 557 1.1 mrg } 558 1.1 mrg } 559 1.1 mrg else if (auto ae = e.e1.isIndexExp()) 560 1.1 mrg { 561 1.1 mrg // Convert &array[n] to &array+n 562 1.1 mrg if (ae.e2.isIntegerExp() && ae.e1.isVarExp()) 563 1.1 mrg { 564 1.1 mrg sinteger_t index = ae.e2.toInteger(); 565 1.1 mrg VarExp ve = ae.e1.isVarExp(); 566 1.1 mrg if (ve.type.isTypeSArray() && !ve.var.isImportedSymbol()) 567 1.1 mrg { 568 1.1 mrg TypeSArray ts = ve.type.isTypeSArray(); 569 1.1 mrg sinteger_t dim = ts.dim.toInteger(); 570 1.1 mrg if (index < 0 || index >= dim) 571 1.1 mrg { 572 1.1 mrg /* 0 for C static arrays means size is unknown, no need to check, 573 1.1 mrg * and address one past the end is OK, too 574 1.1 mrg */ 575 1.1 mrg if (!((dim == 0 || dim == index) && ve.var.isCsymbol())) 576 1.1 mrg { 577 1.1 mrg e.error("array index %lld is out of bounds `[0..%lld]`", index, dim); 578 1.1 mrg return error(); 579 1.1 mrg } 580 1.1 mrg } 581 1.1 mrg 582 1.1 mrg import core.checkedint : mulu; 583 1.1 mrg bool overflow; 584 1.1 mrg const offset = mulu(index, ts.nextOf().size(e.loc), overflow); 585 1.1 mrg if (overflow) 586 1.1 mrg { 587 1.1 mrg e.error("array offset overflow"); 588 1.1 mrg return error(); 589 1.1 mrg } 590 1.1 mrg 591 1.1 mrg ret = new SymOffExp(e.loc, ve.var, offset); 592 1.1 mrg ret.type = e.type; 593 1.1 mrg return; 594 1.1 mrg } 595 1.1 mrg } 596 1.1 mrg // Convert &((a.b)[index]) to (&a.b)+index*elementsize 597 1.1 mrg else if (ae.e2.isIntegerExp() && ae.e1.isDotVarExp()) 598 1.1 mrg { 599 1.1 mrg sinteger_t index = ae.e2.toInteger(); 600 1.1 mrg DotVarExp ve = ae.e1.isDotVarExp(); 601 1.1 mrg if (ve.type.isTypeSArray() && ve.var.isField() && ve.e1.isPtrExp()) 602 1.1 mrg { 603 1.1 mrg TypeSArray ts = ve.type.isTypeSArray(); 604 1.1 mrg sinteger_t dim = ts.dim.toInteger(); 605 1.1 mrg if (index < 0 || index >= dim) 606 1.1 mrg { 607 1.1 mrg /* 0 for C static arrays means size is unknown, no need to check, 608 1.1 mrg * and address one past the end is OK, too 609 1.1 mrg */ 610 1.1 mrg if (!((dim == 0 || dim == index) && ve.var.isCsymbol())) 611 1.1 mrg { 612 1.1 mrg e.error("array index %lld is out of bounds `[0..%lld]`", index, dim); 613 1.1 mrg return error(); 614 1.1 mrg } 615 1.1 mrg } 616 1.1 mrg 617 1.1 mrg import core.checkedint : mulu; 618 1.1 mrg bool overflow; 619 1.1 mrg const offset = mulu(index, ts.nextOf().size(e.loc), overflow); // index*elementsize 620 1.1 mrg if (overflow) 621 1.1 mrg { 622 1.1 mrg e.error("array offset overflow"); 623 1.1 mrg return error(); 624 1.1 mrg } 625 1.1 mrg 626 1.1 mrg auto pe = new AddrExp(e.loc, ve); 627 1.1 mrg pe.type = e.type; 628 1.1 mrg ret = new AddExp(e.loc, pe, new IntegerExp(e.loc, offset, Type.tsize_t)); 629 1.1 mrg ret.type = e.type; 630 1.1 mrg return; 631 1.1 mrg } 632 1.1 mrg } 633 1.1 mrg } 634 1.1 mrg } 635 1.1 mrg 636 1.1 mrg void visitPtr(PtrExp e) 637 1.1 mrg { 638 1.1 mrg //printf("PtrExp::optimize(result = x%x) %s\n", result, e.toChars()); 639 1.1 mrg if (expOptimize(e.e1, result)) 640 1.1 mrg return; 641 1.1 mrg // Convert *&ex to ex 642 1.1 mrg // But only if there is no type punning involved 643 1.1 mrg if (auto ey = e.e1.isAddrExp()) 644 1.1 mrg { 645 1.1 mrg Expression ex = ey.e1; 646 1.1 mrg if (e.type.equals(ex.type)) 647 1.1 mrg ret = ex; 648 1.1 mrg else if (e.type.toBasetype().equivalent(ex.type.toBasetype())) 649 1.1 mrg { 650 1.1 mrg ret = ex.copy(); 651 1.1 mrg ret.type = e.type; 652 1.1 mrg } 653 1.1 mrg } 654 1.1 mrg if (keepLvalue) 655 1.1 mrg return; 656 1.1 mrg // Constant fold *(&structliteral + offset) 657 1.1 mrg if (e.e1.op == EXP.add) 658 1.1 mrg { 659 1.1 mrg Expression ex = Ptr(e.type, e.e1).copy(); 660 1.1 mrg if (!CTFEExp.isCantExp(ex)) 661 1.1 mrg { 662 1.1 mrg ret = ex; 663 1.1 mrg return; 664 1.1 mrg } 665 1.1 mrg } 666 1.1 mrg if (auto se = e.e1.isSymOffExp()) 667 1.1 mrg { 668 1.1 mrg VarDeclaration v = se.var.isVarDeclaration(); 669 1.1 mrg Expression ex = expandVar(result, v); 670 1.1 mrg if (ex && ex.isStructLiteralExp()) 671 1.1 mrg { 672 1.1 mrg StructLiteralExp sle = ex.isStructLiteralExp(); 673 1.1 mrg ex = sle.getField(e.type, cast(uint)se.offset); 674 1.1 mrg if (ex && !CTFEExp.isCantExp(ex)) 675 1.1 mrg { 676 1.1 mrg ret = ex; 677 1.1 mrg return; 678 1.1 mrg } 679 1.1 mrg } 680 1.1 mrg } 681 1.1 mrg } 682 1.1 mrg 683 1.1 mrg void visitDotVar(DotVarExp e) 684 1.1 mrg { 685 1.1 mrg //printf("DotVarExp::optimize(result = x%x) %s\n", result, e.toChars()); 686 1.1 mrg if (expOptimize(e.e1, result)) 687 1.1 mrg return; 688 1.1 mrg if (keepLvalue) 689 1.1 mrg return; 690 1.1 mrg Expression ex = e.e1; 691 1.1 mrg if (auto ve = ex.isVarExp()) 692 1.1 mrg { 693 1.1 mrg VarDeclaration v = ve.var.isVarDeclaration(); 694 1.1 mrg ex = expandVar(result, v); 695 1.1 mrg } 696 1.1 mrg if (ex && ex.isStructLiteralExp()) 697 1.1 mrg { 698 1.1 mrg StructLiteralExp sle = ex.isStructLiteralExp(); 699 1.1 mrg VarDeclaration vf = e.var.isVarDeclaration(); 700 1.1 mrg if (vf && !vf.overlapped) 701 1.1 mrg { 702 1.1 mrg /* https://issues.dlang.org/show_bug.cgi?id=13021 703 1.1 mrg * Prevent optimization if vf has overlapped fields. 704 1.1 mrg */ 705 1.1 mrg ex = sle.getField(e.type, vf.offset); 706 1.1 mrg if (ex && !CTFEExp.isCantExp(ex)) 707 1.1 mrg { 708 1.1 mrg ret = ex; 709 1.1 mrg return; 710 1.1 mrg } 711 1.1 mrg } 712 1.1 mrg } 713 1.1 mrg } 714 1.1 mrg 715 1.1 mrg void visitNew(NewExp e) 716 1.1 mrg { 717 1.1 mrg expOptimize(e.thisexp, WANTvalue); 718 1.1 mrg // Optimize parameters 719 1.1 mrg if (e.arguments) 720 1.1 mrg { 721 1.1 mrg foreach (ref arg; (*e.arguments)[]) 722 1.1 mrg { 723 1.1 mrg expOptimize(arg, WANTvalue); 724 1.1 mrg } 725 1.1 mrg } 726 1.1 mrg } 727 1.1 mrg 728 1.1 mrg void visitCall(CallExp e) 729 1.1 mrg { 730 1.1 mrg //printf("CallExp::optimize(result = %d) %s\n", result, e.toChars()); 731 1.1 mrg // Optimize parameters with keeping lvalue-ness 732 1.1 mrg if (expOptimize(e.e1, result)) 733 1.1 mrg return; 734 1.1 mrg if (e.arguments) 735 1.1 mrg { 736 1.1 mrg Type t1 = e.e1.type.toBasetype(); 737 1.1 mrg if (auto td = t1.isTypeDelegate()) 738 1.1 mrg t1 = td.next; 739 1.1 mrg // t1 can apparently be void for __ArrayDtor(T) calls 740 1.1 mrg if (auto tf = t1.isTypeFunction()) 741 1.1 mrg { 742 1.1 mrg foreach (i, ref arg; (*e.arguments)[]) 743 1.1 mrg { 744 1.1 mrg Parameter p = tf.parameterList[i]; 745 1.1 mrg bool keep = p && p.isReference(); 746 1.1 mrg expOptimize(arg, WANTvalue, keep); 747 1.1 mrg } 748 1.1 mrg } 749 1.1 mrg } 750 1.1 mrg } 751 1.1 mrg 752 1.1 mrg void visitCast(CastExp e) 753 1.1 mrg { 754 1.1 mrg //printf("CastExp::optimize(result = %d) %s\n", result, e.toChars()); 755 1.1 mrg //printf("from %s to %s\n", e.type.toChars(), e.to.toChars()); 756 1.1 mrg //printf("from %s\n", e.type.toChars()); 757 1.1 mrg //printf("e1.type %s\n", e.e1.type.toChars()); 758 1.1 mrg //printf("type = %p\n", e.type); 759 1.1 mrg assert(e.type); 760 1.1 mrg const op1 = e.e1.op; 761 1.1 mrg Expression e1old = e.e1; 762 1.1 mrg if (expOptimize(e.e1, result, keepLvalue)) 763 1.1 mrg return; 764 1.1 mrg if (!keepLvalue) 765 1.1 mrg e.e1 = fromConstInitializer(result, e.e1); 766 1.1 mrg if (e.e1 == e1old && e.e1.op == EXP.arrayLiteral && e.type.toBasetype().ty == Tpointer && e.e1.type.toBasetype().ty != Tsarray) 767 1.1 mrg { 768 1.1 mrg // Casting this will result in the same expression, and 769 1.1 mrg // infinite loop because of Expression::implicitCastTo() 770 1.1 mrg return; // no change 771 1.1 mrg } 772 1.1 mrg if ((e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral) && 773 1.1 mrg (e.type.ty == Tpointer || e.type.ty == Tarray)) 774 1.1 mrg { 775 1.1 mrg const esz = e.type.nextOf().size(e.loc); 776 1.1 mrg const e1sz = e.e1.type.toBasetype().nextOf().size(e.e1.loc); 777 1.1 mrg if (esz == SIZE_INVALID || e1sz == SIZE_INVALID) 778 1.1 mrg return error(); 779 1.1 mrg 780 1.1 mrg if (e1sz == esz) 781 1.1 mrg { 782 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=12937 783 1.1 mrg // If target type is void array, trying to paint 784 1.1 mrg // e.e1 with that type will cause infinite recursive optimization. 785 1.1 mrg if (e.type.nextOf().ty == Tvoid) 786 1.1 mrg return; 787 1.1 mrg ret = e.e1.castTo(null, e.type); 788 1.1 mrg //printf(" returning1 %s\n", ret.toChars()); 789 1.1 mrg return; 790 1.1 mrg } 791 1.1 mrg } 792 1.1 mrg 793 1.1 mrg // Returning e.e1 with changing its type 794 1.1 mrg void returnE_e1() 795 1.1 mrg { 796 1.1 mrg ret = (e1old == e.e1 ? e.e1.copy() : e.e1); 797 1.1 mrg ret.type = e.type; 798 1.1 mrg } 799 1.1 mrg 800 1.1 mrg if (e.e1.op == EXP.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant) 801 1.1 mrg { 802 1.1 mrg //printf(" returning2 %s\n", e.e1.toChars()); 803 1.1 mrg return returnE_e1(); 804 1.1 mrg } 805 1.1 mrg /* The first test here is to prevent infinite loops 806 1.1 mrg */ 807 1.1 mrg if (op1 != EXP.arrayLiteral && e.e1.op == EXP.arrayLiteral) 808 1.1 mrg { 809 1.1 mrg ret = e.e1.castTo(null, e.to); 810 1.1 mrg return; 811 1.1 mrg } 812 1.1 mrg if (e.e1.op == EXP.null_ && (e.type.ty == Tpointer || e.type.ty == Tclass || e.type.ty == Tarray)) 813 1.1 mrg { 814 1.1 mrg //printf(" returning3 %s\n", e.e1.toChars()); 815 1.1 mrg return returnE_e1(); 816 1.1 mrg } 817 1.1 mrg if (e.type.ty == Tclass && e.e1.type.ty == Tclass) 818 1.1 mrg { 819 1.1 mrg import dmd.astenums : Sizeok; 820 1.1 mrg 821 1.1 mrg // See if we can remove an unnecessary cast 822 1.1 mrg ClassDeclaration cdfrom = e.e1.type.isClassHandle(); 823 1.1 mrg ClassDeclaration cdto = e.type.isClassHandle(); 824 1.1 mrg if (cdfrom.errors || cdto.errors) 825 1.1 mrg return error(); 826 1.1 mrg if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration()) 827 1.1 mrg return returnE_e1(); // can always convert a class to Object 828 1.1 mrg // Need to determine correct offset before optimizing away the cast. 829 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=16980 830 1.1 mrg cdfrom.size(e.loc); 831 1.1 mrg assert(cdfrom.sizeok == Sizeok.done); 832 1.1 mrg assert(cdto.sizeok == Sizeok.done || !cdto.isBaseOf(cdfrom, null)); 833 1.1 mrg int offset; 834 1.1 mrg if (cdto.isBaseOf(cdfrom, &offset) && offset == 0) 835 1.1 mrg { 836 1.1 mrg //printf(" returning4 %s\n", e.e1.toChars()); 837 1.1 mrg return returnE_e1(); 838 1.1 mrg } 839 1.1 mrg } 840 1.1 mrg if (e.e1.type.mutableOf().unSharedOf().equals(e.to.mutableOf().unSharedOf())) 841 1.1 mrg { 842 1.1 mrg //printf(" returning5 %s\n", e.e1.toChars()); 843 1.1 mrg return returnE_e1(); 844 1.1 mrg } 845 1.1 mrg if (e.e1.isConst()) 846 1.1 mrg { 847 1.1 mrg if (e.e1.op == EXP.symbolOffset) 848 1.1 mrg { 849 1.1 mrg if (e.type.toBasetype().ty != Tsarray) 850 1.1 mrg { 851 1.1 mrg const esz = e.type.size(e.loc); 852 1.1 mrg const e1sz = e.e1.type.size(e.e1.loc); 853 1.1 mrg if (esz == SIZE_INVALID || 854 1.1 mrg e1sz == SIZE_INVALID) 855 1.1 mrg return error(); 856 1.1 mrg 857 1.1 mrg if (esz == e1sz) 858 1.1 mrg return returnE_e1(); 859 1.1 mrg } 860 1.1 mrg return; 861 1.1 mrg } 862 1.1 mrg if (e.to.toBasetype().ty != Tvoid) 863 1.1 mrg { 864 1.1 mrg if (e.e1.type.equals(e.type) && e.type.equals(e.to)) 865 1.1 mrg ret = e.e1; 866 1.1 mrg else 867 1.1 mrg ret = Cast(e.loc, e.type, e.to, e.e1).copy(); 868 1.1 mrg } 869 1.1 mrg } 870 1.1 mrg //printf(" returning6 %s\n", ret.toChars()); 871 1.1 mrg } 872 1.1 mrg 873 1.1 mrg void visitBinAssign(BinAssignExp e) 874 1.1 mrg { 875 1.1 mrg //printf("BinAssignExp::optimize(result = %d) %s\n", result, e.toChars()); 876 1.1 mrg if (binOptimize(e, result, /*keepLhsLvalue*/ true)) 877 1.1 mrg return; 878 1.1 mrg if (e.op == EXP.leftShiftAssign || e.op == EXP.rightShiftAssign || e.op == EXP.unsignedRightShiftAssign) 879 1.1 mrg { 880 1.1 mrg if (e.e2.isConst() == 1) 881 1.1 mrg { 882 1.1 mrg sinteger_t i2 = e.e2.toInteger(); 883 1.1 mrg uinteger_t sz = e.e1.type.size(e.e1.loc); 884 1.1 mrg assert(sz != SIZE_INVALID); 885 1.1 mrg sz *= 8; 886 1.1 mrg if (i2 < 0 || i2 >= sz) 887 1.1 mrg { 888 1.1 mrg e.error("shift assign by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1); 889 1.1 mrg return error(); 890 1.1 mrg } 891 1.1 mrg } 892 1.1 mrg } 893 1.1 mrg } 894 1.1 mrg 895 1.1 mrg void visitBin(BinExp e) 896 1.1 mrg { 897 1.1 mrg //printf("BinExp::optimize(result = %d) %s\n", result, e.toChars()); 898 1.1 mrg const keepLhsLvalue = e.op == EXP.construct || e.op == EXP.blit || e.op == EXP.assign 899 1.1 mrg || e.op == EXP.plusPlus || e.op == EXP.minusMinus 900 1.1 mrg || e.op == EXP.prePlusPlus || e.op == EXP.preMinusMinus; 901 1.1 mrg binOptimize(e, result, keepLhsLvalue); 902 1.1 mrg } 903 1.1 mrg 904 1.1 mrg void visitAdd(AddExp e) 905 1.1 mrg { 906 1.1 mrg //printf("AddExp::optimize(%s)\n", e.toChars()); 907 1.1 mrg if (binOptimize(e, result)) 908 1.1 mrg return; 909 1.1 mrg if (e.e1.isConst() && e.e2.isConst()) 910 1.1 mrg { 911 1.1 mrg if (e.e1.op == EXP.symbolOffset && e.e2.op == EXP.symbolOffset) 912 1.1 mrg return; 913 1.1 mrg ret = Add(e.loc, e.type, e.e1, e.e2).copy(); 914 1.1 mrg } 915 1.1 mrg } 916 1.1 mrg 917 1.1 mrg void visitMin(MinExp e) 918 1.1 mrg { 919 1.1 mrg //printf("MinExp::optimize(%s)\n", e.toChars()); 920 1.1 mrg if (binOptimize(e, result)) 921 1.1 mrg return; 922 1.1 mrg if (e.e1.isConst() && e.e2.isConst()) 923 1.1 mrg { 924 1.1 mrg if (e.e2.op == EXP.symbolOffset) 925 1.1 mrg return; 926 1.1 mrg ret = Min(e.loc, e.type, e.e1, e.e2).copy(); 927 1.1 mrg } 928 1.1 mrg } 929 1.1 mrg 930 1.1 mrg void visitMul(MulExp e) 931 1.1 mrg { 932 1.1 mrg //printf("MulExp::optimize(result = %d) %s\n", result, e.toChars()); 933 1.1 mrg if (binOptimize(e, result)) 934 1.1 mrg return; 935 1.1 mrg if (e.e1.isConst() == 1 && e.e2.isConst() == 1) 936 1.1 mrg { 937 1.1 mrg ret = Mul(e.loc, e.type, e.e1, e.e2).copy(); 938 1.1 mrg } 939 1.1 mrg } 940 1.1 mrg 941 1.1 mrg void visitDiv(DivExp e) 942 1.1 mrg { 943 1.1 mrg //printf("DivExp::optimize(%s)\n", e.toChars()); 944 1.1 mrg if (binOptimize(e, result)) 945 1.1 mrg return; 946 1.1 mrg if (e.e1.isConst() == 1 && e.e2.isConst() == 1) 947 1.1 mrg { 948 1.1 mrg ret = Div(e.loc, e.type, e.e1, e.e2).copy(); 949 1.1 mrg } 950 1.1 mrg } 951 1.1 mrg 952 1.1 mrg void visitMod(ModExp e) 953 1.1 mrg { 954 1.1 mrg if (binOptimize(e, result)) 955 1.1 mrg return; 956 1.1 mrg if (e.e1.isConst() == 1 && e.e2.isConst() == 1) 957 1.1 mrg { 958 1.1 mrg ret = Mod(e.loc, e.type, e.e1, e.e2).copy(); 959 1.1 mrg } 960 1.1 mrg } 961 1.1 mrg 962 1.1 mrg extern (D) void shift_optimize(BinExp e, UnionExp function(const ref Loc, Type, Expression, Expression) shift) 963 1.1 mrg { 964 1.1 mrg if (binOptimize(e, result)) 965 1.1 mrg return; 966 1.1 mrg if (e.e2.isConst() == 1) 967 1.1 mrg { 968 1.1 mrg sinteger_t i2 = e.e2.toInteger(); 969 1.1 mrg uinteger_t sz = e.e1.type.size(e.e1.loc); 970 1.1 mrg assert(sz != SIZE_INVALID); 971 1.1 mrg sz *= 8; 972 1.1 mrg if (i2 < 0 || i2 >= sz) 973 1.1 mrg { 974 1.1 mrg e.error("shift by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1); 975 1.1 mrg return error(); 976 1.1 mrg } 977 1.1 mrg if (e.e1.isConst() == 1) 978 1.1 mrg ret = (*shift)(e.loc, e.type, e.e1, e.e2).copy(); 979 1.1 mrg } 980 1.1 mrg } 981 1.1 mrg 982 1.1 mrg void visitShl(ShlExp e) 983 1.1 mrg { 984 1.1 mrg //printf("ShlExp::optimize(result = %d) %s\n", result, e.toChars()); 985 1.1 mrg shift_optimize(e, &Shl); 986 1.1 mrg } 987 1.1 mrg 988 1.1 mrg void visitShr(ShrExp e) 989 1.1 mrg { 990 1.1 mrg //printf("ShrExp::optimize(result = %d) %s\n", result, e.toChars()); 991 1.1 mrg shift_optimize(e, &Shr); 992 1.1 mrg } 993 1.1 mrg 994 1.1 mrg void visitUshr(UshrExp e) 995 1.1 mrg { 996 1.1 mrg //printf("UshrExp::optimize(result = %d) %s\n", result, toChars()); 997 1.1 mrg shift_optimize(e, &Ushr); 998 1.1 mrg } 999 1.1 mrg 1000 1.1 mrg void visitAnd(AndExp e) 1001 1.1 mrg { 1002 1.1 mrg if (binOptimize(e, result)) 1003 1.1 mrg return; 1004 1.1 mrg if (e.e1.isConst() == 1 && e.e2.isConst() == 1) 1005 1.1 mrg ret = And(e.loc, e.type, e.e1, e.e2).copy(); 1006 1.1 mrg } 1007 1.1 mrg 1008 1.1 mrg void visitOr(OrExp e) 1009 1.1 mrg { 1010 1.1 mrg if (binOptimize(e, result)) 1011 1.1 mrg return; 1012 1.1 mrg if (e.e1.isConst() == 1 && e.e2.isConst() == 1) 1013 1.1 mrg ret = Or(e.loc, e.type, e.e1, e.e2).copy(); 1014 1.1 mrg } 1015 1.1 mrg 1016 1.1 mrg void visitXor(XorExp e) 1017 1.1 mrg { 1018 1.1 mrg if (binOptimize(e, result)) 1019 1.1 mrg return; 1020 1.1 mrg if (e.e1.isConst() == 1 && e.e2.isConst() == 1) 1021 1.1 mrg ret = Xor(e.loc, e.type, e.e1, e.e2).copy(); 1022 1.1 mrg } 1023 1.1 mrg 1024 1.1 mrg void visitPow(PowExp e) 1025 1.1 mrg { 1026 1.1 mrg if (binOptimize(e, result)) 1027 1.1 mrg return; 1028 1.1 mrg // All negative integral powers are illegal. 1029 1.1 mrg if (e.e1.type.isintegral() && (e.e2.op == EXP.int64) && cast(sinteger_t)e.e2.toInteger() < 0) 1030 1.1 mrg { 1031 1.1 mrg e.error("cannot raise `%s` to a negative integer power. Did you mean `(cast(real)%s)^^%s` ?", e.e1.type.toBasetype().toChars(), e.e1.toChars(), e.e2.toChars()); 1032 1.1 mrg return error(); 1033 1.1 mrg } 1034 1.1 mrg // If e2 *could* have been an integer, make it one. 1035 1.1 mrg if (e.e2.op == EXP.float64 && e.e2.toReal() == real_t(cast(sinteger_t)e.e2.toReal())) 1036 1.1 mrg { 1037 1.1 mrg // This only applies to floating point, or positive integral powers. 1038 1.1 mrg if (e.e1.type.isfloating() || cast(sinteger_t)e.e2.toInteger() >= 0) 1039 1.1 mrg e.e2 = new IntegerExp(e.loc, e.e2.toInteger(), Type.tint64); 1040 1.1 mrg } 1041 1.1 mrg if (e.e1.isConst() == 1 && e.e2.isConst() == 1) 1042 1.1 mrg { 1043 1.1 mrg Expression ex = Pow(e.loc, e.type, e.e1, e.e2).copy(); 1044 1.1 mrg if (!CTFEExp.isCantExp(ex)) 1045 1.1 mrg { 1046 1.1 mrg ret = ex; 1047 1.1 mrg return; 1048 1.1 mrg } 1049 1.1 mrg } 1050 1.1 mrg } 1051 1.1 mrg 1052 1.1 mrg void visitComma(CommaExp e) 1053 1.1 mrg { 1054 1.1 mrg //printf("CommaExp::optimize(result = %d) %s\n", result, e.toChars()); 1055 1.1 mrg // Comma needs special treatment, because it may 1056 1.1 mrg // contain compiler-generated declarations. We can interpret them, but 1057 1.1 mrg // otherwise we must NOT attempt to constant-fold them. 1058 1.1 mrg // In particular, if the comma returns a temporary variable, it needs 1059 1.1 mrg // to be an lvalue (this is particularly important for struct constructors) 1060 1.1 mrg expOptimize(e.e1, WANTvalue); 1061 1.1 mrg expOptimize(e.e2, result, keepLvalue); 1062 1.1 mrg if (ret.op == EXP.error) 1063 1.1 mrg return; 1064 1.1 mrg if (!e.e1 || e.e1.op == EXP.int64 || e.e1.op == EXP.float64 || !hasSideEffect(e.e1)) 1065 1.1 mrg { 1066 1.1 mrg ret = e.e2; 1067 1.1 mrg if (ret) 1068 1.1 mrg ret.type = e.type; 1069 1.1 mrg } 1070 1.1 mrg //printf("-CommaExp::optimize(result = %d) %s\n", result, e.e.toChars()); 1071 1.1 mrg } 1072 1.1 mrg 1073 1.1 mrg void visitArrayLength(ArrayLengthExp e) 1074 1.1 mrg { 1075 1.1 mrg //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, e.toChars()); 1076 1.1 mrg if (unaOptimize(e, WANTexpand)) 1077 1.1 mrg return; 1078 1.1 mrg // CTFE interpret static immutable arrays (to get better diagnostics) 1079 1.1 mrg if (auto ve = e.e1.isVarExp()) 1080 1.1 mrg { 1081 1.1 mrg VarDeclaration v = ve.var.isVarDeclaration(); 1082 1.1 mrg if (v && (v.storage_class & STC.static_) && (v.storage_class & STC.immutable_) && v._init) 1083 1.1 mrg { 1084 1.1 mrg if (Expression ci = v.getConstInitializer()) 1085 1.1 mrg e.e1 = ci; 1086 1.1 mrg } 1087 1.1 mrg } 1088 1.1 mrg if (e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral || e.e1.op == EXP.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray) 1089 1.1 mrg { 1090 1.1 mrg ret = ArrayLength(e.type, e.e1).copy(); 1091 1.1 mrg } 1092 1.1 mrg } 1093 1.1 mrg 1094 1.1 mrg void visitEqual(EqualExp e) 1095 1.1 mrg { 1096 1.1 mrg //printf("EqualExp::optimize(result = %x) %s\n", result, e.toChars()); 1097 1.1 mrg if (binOptimize(e, WANTvalue)) 1098 1.1 mrg return; 1099 1.1 mrg Expression e1 = fromConstInitializer(result, e.e1); 1100 1.1 mrg Expression e2 = fromConstInitializer(result, e.e2); 1101 1.1 mrg if (e1.op == EXP.error) 1102 1.1 mrg { 1103 1.1 mrg ret = e1; 1104 1.1 mrg return; 1105 1.1 mrg } 1106 1.1 mrg if (e2.op == EXP.error) 1107 1.1 mrg { 1108 1.1 mrg ret = e2; 1109 1.1 mrg return; 1110 1.1 mrg } 1111 1.1 mrg ret = Equal(e.op, e.loc, e.type, e1, e2).copy(); 1112 1.1 mrg if (CTFEExp.isCantExp(ret)) 1113 1.1 mrg ret = e; 1114 1.1 mrg } 1115 1.1 mrg 1116 1.1 mrg void visitIdentity(IdentityExp e) 1117 1.1 mrg { 1118 1.1 mrg //printf("IdentityExp::optimize(result = %d) %s\n", result, e.toChars()); 1119 1.1 mrg if (binOptimize(e, WANTvalue)) 1120 1.1 mrg return; 1121 1.1 mrg if ((e.e1.isConst() && e.e2.isConst()) || (e.e1.op == EXP.null_ && e.e2.op == EXP.null_)) 1122 1.1 mrg { 1123 1.1 mrg ret = Identity(e.op, e.loc, e.type, e.e1, e.e2).copy(); 1124 1.1 mrg if (CTFEExp.isCantExp(ret)) 1125 1.1 mrg ret = e; 1126 1.1 mrg } 1127 1.1 mrg } 1128 1.1 mrg 1129 1.1 mrg void visitIndex(IndexExp e) 1130 1.1 mrg { 1131 1.1 mrg //printf("IndexExp::optimize(result = %d) %s\n", result, e.toChars()); 1132 1.1 mrg if (expOptimize(e.e1, result & WANTexpand)) 1133 1.1 mrg return; 1134 1.1 mrg Expression ex = fromConstInitializer(result, e.e1); 1135 1.1 mrg // We might know $ now 1136 1.1 mrg setLengthVarIfKnown(e.lengthVar, ex); 1137 1.1 mrg if (expOptimize(e.e2, WANTvalue)) 1138 1.1 mrg return; 1139 1.1 mrg // Don't optimize to an array literal element directly in case an lvalue is requested 1140 1.1 mrg if (keepLvalue && ex.op == EXP.arrayLiteral) 1141 1.1 mrg return; 1142 1.1 mrg ret = Index(e.type, ex, e.e2, e.indexIsInBounds).copy(); 1143 1.1 mrg if (CTFEExp.isCantExp(ret) || (!ret.isErrorExp() && keepLvalue && !ret.isLvalue())) 1144 1.1 mrg ret = e; 1145 1.1 mrg } 1146 1.1 mrg 1147 1.1 mrg void visitSlice(SliceExp e) 1148 1.1 mrg { 1149 1.1 mrg //printf("SliceExp::optimize(result = %d) %s\n", result, e.toChars()); 1150 1.1 mrg if (expOptimize(e.e1, result & WANTexpand)) 1151 1.1 mrg return; 1152 1.1 mrg if (!e.lwr) 1153 1.1 mrg { 1154 1.1 mrg if (e.e1.op == EXP.string_) 1155 1.1 mrg { 1156 1.1 mrg // Convert slice of string literal into dynamic array 1157 1.1 mrg Type t = e.e1.type.toBasetype(); 1158 1.1 mrg if (Type tn = t.nextOf()) 1159 1.1 mrg ret = e.e1.castTo(null, tn.arrayOf()); 1160 1.1 mrg } 1161 1.1 mrg } 1162 1.1 mrg else 1163 1.1 mrg { 1164 1.1 mrg e.e1 = fromConstInitializer(result, e.e1); 1165 1.1 mrg // We might know $ now 1166 1.1 mrg setLengthVarIfKnown(e.lengthVar, e.e1); 1167 1.1 mrg expOptimize(e.lwr, WANTvalue); 1168 1.1 mrg expOptimize(e.upr, WANTvalue); 1169 1.1 mrg if (ret.op == EXP.error) 1170 1.1 mrg return; 1171 1.1 mrg ret = Slice(e.type, e.e1, e.lwr, e.upr).copy(); 1172 1.1 mrg if (CTFEExp.isCantExp(ret)) 1173 1.1 mrg ret = e; 1174 1.1 mrg } 1175 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=14649 1176 1.1 mrg // Leave the slice form so it might be 1177 1.1 mrg // a part of array operation. 1178 1.1 mrg // Assume that the backend codegen will handle the form `e[]` 1179 1.1 mrg // as an equal to `e` itself. 1180 1.1 mrg if (ret.op == EXP.string_) 1181 1.1 mrg { 1182 1.1 mrg e.e1 = ret; 1183 1.1 mrg e.lwr = null; 1184 1.1 mrg e.upr = null; 1185 1.1 mrg ret = e; 1186 1.1 mrg } 1187 1.1 mrg //printf("-SliceExp::optimize() %s\n", ret.toChars()); 1188 1.1 mrg } 1189 1.1 mrg 1190 1.1 mrg void visitLogical(LogicalExp e) 1191 1.1 mrg { 1192 1.1 mrg //printf("LogicalExp::optimize(%d) %s\n", result, e.toChars()); 1193 1.1 mrg if (expOptimize(e.e1, WANTvalue)) 1194 1.1 mrg return; 1195 1.1 mrg const oror = e.op == EXP.orOr; 1196 1.1 mrg if (e.e1.toBool().hasValue(oror)) 1197 1.1 mrg { 1198 1.1 mrg // Replace with (e1, oror) 1199 1.1 mrg ret = IntegerExp.createBool(oror); 1200 1.1 mrg ret = Expression.combine(e.e1, ret); 1201 1.1 mrg if (e.type.toBasetype().ty == Tvoid) 1202 1.1 mrg { 1203 1.1 mrg ret = new CastExp(e.loc, ret, Type.tvoid); 1204 1.1 mrg ret.type = e.type; 1205 1.1 mrg } 1206 1.1 mrg ret = Expression_optimize(ret, result, false); 1207 1.1 mrg return; 1208 1.1 mrg } 1209 1.1 mrg expOptimize(e.e2, WANTvalue); 1210 1.1 mrg if (e.e1.isConst()) 1211 1.1 mrg { 1212 1.1 mrg const e1Opt = e.e1.toBool(); 1213 1.1 mrg if (e.e2.isConst()) 1214 1.1 mrg { 1215 1.1 mrg bool n1 = e1Opt.get(); 1216 1.1 mrg bool n2 = e.e2.toBool().get(); 1217 1.1 mrg ret = new IntegerExp(e.loc, oror ? (n1 || n2) : (n1 && n2), e.type); 1218 1.1 mrg } 1219 1.1 mrg else if (e1Opt.hasValue(!oror)) 1220 1.1 mrg { 1221 1.1 mrg if (e.type.toBasetype().ty == Tvoid) 1222 1.1 mrg ret = e.e2; 1223 1.1 mrg else 1224 1.1 mrg { 1225 1.1 mrg ret = new CastExp(e.loc, e.e2, e.type); 1226 1.1 mrg ret.type = e.type; 1227 1.1 mrg } 1228 1.1 mrg } 1229 1.1 mrg } 1230 1.1 mrg } 1231 1.1 mrg 1232 1.1 mrg void visitCmp(CmpExp e) 1233 1.1 mrg { 1234 1.1 mrg //printf("CmpExp::optimize() %s\n", e.toChars()); 1235 1.1 mrg if (binOptimize(e, WANTvalue)) 1236 1.1 mrg return; 1237 1.1 mrg Expression e1 = fromConstInitializer(result, e.e1); 1238 1.1 mrg Expression e2 = fromConstInitializer(result, e.e2); 1239 1.1 mrg ret = Cmp(e.op, e.loc, e.type, e1, e2).copy(); 1240 1.1 mrg if (CTFEExp.isCantExp(ret)) 1241 1.1 mrg ret = e; 1242 1.1 mrg } 1243 1.1 mrg 1244 1.1 mrg void visitCat(CatExp e) 1245 1.1 mrg { 1246 1.1 mrg //printf("CatExp::optimize(%d) %s\n", result, e.toChars()); 1247 1.1 mrg if (binOptimize(e, result)) 1248 1.1 mrg return; 1249 1.1 mrg if (auto ce1 = e.e1.isCatExp()) 1250 1.1 mrg { 1251 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=12798 1252 1.1 mrg // optimize ((expr ~ str1) ~ str2) 1253 1.1 mrg scope CatExp cex = new CatExp(e.loc, ce1.e2, e.e2); 1254 1.1 mrg cex.type = e.type; 1255 1.1 mrg Expression ex = Expression_optimize(cex, result, false); 1256 1.1 mrg if (ex != cex) 1257 1.1 mrg { 1258 1.1 mrg e.e1 = ce1.e1; 1259 1.1 mrg e.e2 = ex; 1260 1.1 mrg } 1261 1.1 mrg } 1262 1.1 mrg // optimize "str"[] -> "str" 1263 1.1 mrg if (auto se1 = e.e1.isSliceExp()) 1264 1.1 mrg { 1265 1.1 mrg if (se1.e1.op == EXP.string_ && !se1.lwr) 1266 1.1 mrg e.e1 = se1.e1; 1267 1.1 mrg } 1268 1.1 mrg if (auto se2 = e.e2.isSliceExp()) 1269 1.1 mrg { 1270 1.1 mrg if (se2.e1.op == EXP.string_ && !se2.lwr) 1271 1.1 mrg e.e2 = se2.e1; 1272 1.1 mrg } 1273 1.1 mrg ret = Cat(e.loc, e.type, e.e1, e.e2).copy(); 1274 1.1 mrg if (CTFEExp.isCantExp(ret)) 1275 1.1 mrg ret = e; 1276 1.1 mrg } 1277 1.1 mrg 1278 1.1 mrg void visitCond(CondExp e) 1279 1.1 mrg { 1280 1.1 mrg if (expOptimize(e.econd, WANTvalue)) 1281 1.1 mrg return; 1282 1.1 mrg const opt = e.econd.toBool(); 1283 1.1 mrg if (opt.hasValue(true)) 1284 1.1 mrg ret = Expression_optimize(e.e1, result, keepLvalue); 1285 1.1 mrg else if (opt.hasValue(false)) 1286 1.1 mrg ret = Expression_optimize(e.e2, result, keepLvalue); 1287 1.1 mrg else 1288 1.1 mrg { 1289 1.1 mrg expOptimize(e.e1, result, keepLvalue); 1290 1.1 mrg expOptimize(e.e2, result, keepLvalue); 1291 1.1 mrg } 1292 1.1 mrg } 1293 1.1 mrg 1294 1.1 mrg // Optimize the expression until it can no longer be simplified. 1295 1.1 mrg size_t b; 1296 1.1 mrg while (1) 1297 1.1 mrg { 1298 1.1 mrg if (b++ == global.recursionLimit) 1299 1.1 mrg { 1300 1.1 mrg e.error("infinite loop while optimizing expression"); 1301 1.1 mrg fatal(); 1302 1.1 mrg } 1303 1.1 mrg 1304 1.1 mrg auto ex = ret; 1305 1.1 mrg switch (ex.op) 1306 1.1 mrg { 1307 1.1 mrg case EXP.variable: visitVar(ex.isVarExp()); break; 1308 1.1 mrg case EXP.tuple: visitTuple(ex.isTupleExp()); break; 1309 1.1 mrg case EXP.arrayLiteral: visitArrayLiteral(ex.isArrayLiteralExp()); break; 1310 1.1 mrg case EXP.assocArrayLiteral: visitAssocArrayLiteral(ex.isAssocArrayLiteralExp()); break; 1311 1.1 mrg case EXP.structLiteral: visitStructLiteral(ex.isStructLiteralExp()); break; 1312 1.1 mrg 1313 1.1 mrg case EXP.import_: 1314 1.1 mrg case EXP.assert_: 1315 1.1 mrg case EXP.dotIdentifier: 1316 1.1 mrg case EXP.dotTemplateDeclaration: 1317 1.1 mrg case EXP.dotTemplateInstance: 1318 1.1 mrg case EXP.delegate_: 1319 1.1 mrg case EXP.dotType: 1320 1.1 mrg case EXP.uadd: 1321 1.1 mrg case EXP.delete_: 1322 1.1 mrg case EXP.vector: 1323 1.1 mrg case EXP.vectorArray: 1324 1.1 mrg case EXP.array: 1325 1.1 mrg case EXP.delegatePointer: 1326 1.1 mrg case EXP.delegateFunctionPointer: 1327 1.1 mrg case EXP.preMinusMinus: 1328 1.1 mrg case EXP.prePlusPlus: visitUna(cast(UnaExp)ex); break; 1329 1.1 mrg 1330 1.1 mrg case EXP.negate: visitNeg(ex.isNegExp()); break; 1331 1.1 mrg case EXP.tilde: visitCom(ex.isComExp()); break; 1332 1.1 mrg case EXP.not: visitNop(ex.isNotExp()); break; 1333 1.1 mrg case EXP.symbolOffset: visitSymOff(ex.isSymOffExp()); break; 1334 1.1 mrg case EXP.address: visitAddr(ex.isAddrExp()); break; 1335 1.1 mrg case EXP.star: visitPtr(ex.isPtrExp()); break; 1336 1.1 mrg case EXP.dotVariable: visitDotVar(ex.isDotVarExp()); break; 1337 1.1 mrg case EXP.new_: visitNew(ex.isNewExp()); break; 1338 1.1 mrg case EXP.call: visitCall(ex.isCallExp()); break; 1339 1.1 mrg case EXP.cast_: visitCast(ex.isCastExp()); break; 1340 1.1 mrg 1341 1.1 mrg case EXP.addAssign: 1342 1.1 mrg case EXP.minAssign: 1343 1.1 mrg case EXP.mulAssign: 1344 1.1 mrg case EXP.divAssign: 1345 1.1 mrg case EXP.modAssign: 1346 1.1 mrg case EXP.andAssign: 1347 1.1 mrg case EXP.orAssign: 1348 1.1 mrg case EXP.xorAssign: 1349 1.1 mrg case EXP.powAssign: 1350 1.1 mrg case EXP.leftShiftAssign: 1351 1.1 mrg case EXP.rightShiftAssign: 1352 1.1 mrg case EXP.unsignedRightShiftAssign: 1353 1.1 mrg case EXP.concatenateElemAssign: 1354 1.1 mrg case EXP.concatenateDcharAssign: 1355 1.1 mrg case EXP.concatenateAssign: visitBinAssign(ex.isBinAssignExp()); break; 1356 1.1 mrg 1357 1.1 mrg case EXP.minusMinus: 1358 1.1 mrg case EXP.plusPlus: 1359 1.1 mrg case EXP.assign: 1360 1.1 mrg case EXP.construct: 1361 1.1 mrg case EXP.blit: 1362 1.1 mrg case EXP.in_: 1363 1.1 mrg case EXP.remove: 1364 1.1 mrg case EXP.dot: visitBin(cast(BinExp)ex); break; 1365 1.1 mrg 1366 1.1 mrg case EXP.add: visitAdd(ex.isAddExp()); break; 1367 1.1 mrg case EXP.min: visitMin(ex.isMinExp()); break; 1368 1.1 mrg case EXP.mul: visitMul(ex.isMulExp()); break; 1369 1.1 mrg case EXP.div: visitDiv(ex.isDivExp()); break; 1370 1.1 mrg case EXP.mod: visitMod(ex.isModExp()); break; 1371 1.1 mrg case EXP.leftShift: visitShl(ex.isShlExp()); break; 1372 1.1 mrg case EXP.rightShift: visitShr(ex.isShrExp()); break; 1373 1.1 mrg case EXP.unsignedRightShift: visitUshr(ex.isUshrExp()); break; 1374 1.1 mrg case EXP.and: visitAnd(ex.isAndExp()); break; 1375 1.1 mrg case EXP.or: visitOr(ex.isOrExp()); break; 1376 1.1 mrg case EXP.xor: visitXor(ex.isXorExp()); break; 1377 1.1 mrg case EXP.pow: visitPow(ex.isPowExp()); break; 1378 1.1 mrg case EXP.comma: visitComma(ex.isCommaExp()); break; 1379 1.1 mrg case EXP.arrayLength: visitArrayLength(ex.isArrayLengthExp()); break; 1380 1.1 mrg case EXP.notEqual: 1381 1.1 mrg case EXP.equal: visitEqual(ex.isEqualExp()); break; 1382 1.1 mrg case EXP.notIdentity: 1383 1.1 mrg case EXP.identity: visitIdentity(ex.isIdentityExp()); break; 1384 1.1 mrg case EXP.index: visitIndex(ex.isIndexExp()); break; 1385 1.1 mrg case EXP.slice: visitSlice(ex.isSliceExp()); break; 1386 1.1 mrg case EXP.andAnd: 1387 1.1 mrg case EXP.orOr: visitLogical(ex.isLogicalExp()); break; 1388 1.1 mrg case EXP.lessThan: 1389 1.1 mrg case EXP.lessOrEqual: 1390 1.1 mrg case EXP.greaterThan: 1391 1.1 mrg case EXP.greaterOrEqual: visitCmp(cast(CmpExp)ex); break; 1392 1.1 mrg case EXP.concatenate: visitCat(ex.isCatExp()); break; 1393 1.1 mrg case EXP.question: visitCond(ex.isCondExp()); break; 1394 1.1 mrg 1395 1.1 mrg default: visitExp(ex); break; 1396 1.1 mrg } 1397 1.1 mrg 1398 1.1 mrg if (ex == ret) 1399 1.1 mrg break; 1400 1.1 mrg } 1401 1.1 mrg return ret; 1402 1.1 mrg } 1403