Hi, This patch merges the D front-end implementation with upstream dmd 8508c4e68. Fixes a performance bug where 'static foreach' would take an exponentially long time to expand during CTFE.
In the following example: static foreach (i; 0..30000) {} Compilation time had been reduced from around 40 to 0.08 seconds. Memory consumption is also reduced from 3.5GB to 55MB. Bootstrapped and regression tested on x86_64-linux-gnu, committed to mainline, and backported to the gcc-10 branch. Regards Iain --- gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 8508c4e68. --- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/cond.c | 73 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 7de89351482..b99e9f3353d 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -4be011355dd2c5e2e54b99f9369d5faeabca2ca5 +8508c4e683f065eb3deab76b610f7fecb3258a8e The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/cond.c b/gcc/d/dmd/cond.c index 12fef59d820..beda133ffdb 100644 --- a/gcc/d/dmd/cond.c +++ b/gcc/d/dmd/cond.c @@ -92,13 +92,23 @@ static void lowerArrayAggregate(StaticForeach *sfe, Scope *sc) el = el->ctfeInterpret(); if (el->op == TOKint64) { - dinteger_t length = el->toInteger(); - Expressions *es = new Expressions(); - for (size_t i = 0; i < length; i++) + Expressions *es; + if (ArrayLiteralExp *ale = aggr->isArrayLiteralExp()) { - IntegerExp *index = new IntegerExp(sfe->loc, i, Type::tsize_t); - Expression *value = new IndexExp(aggr->loc, aggr, index); - es->push(value); + // Directly use the elements of the array for the TupleExp creation + es = ale->elements; + } + else + { + size_t length = (size_t)el->toInteger(); + es = new Expressions(); + es->setDim(length); + for (size_t i = 0; i < length; i++) + { + IntegerExp *index = new IntegerExp(sfe->loc, i, Type::tsize_t); + Expression *value = new IndexExp(aggr->loc, aggr, index); + (*es)[i] = value; + } } sfe->aggrfe->aggr = new TupleExp(aggr->loc, es); sfe->aggrfe->aggr = semantic(sfe->aggrfe->aggr, sc); @@ -307,13 +317,50 @@ static void lowerNonArrayAggregate(StaticForeach *sfe, Scope *sc) Expression *catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]); s2->push(createForeach(sfe, aloc, pparams[1], new ExpStatement(aloc, catass))); s2->push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres))); - Expression *aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2)); - sc = sc->startCTFE(); - aggr = semantic(aggr, sc); - aggr = resolveProperties(sc, aggr); - sc = sc->endCTFE(); - aggr = aggr->optimize(WANTvalue); - aggr = aggr->ctfeInterpret(); + + Expression *aggr; + Type *indexty; + + if (sfe->rangefe && (indexty = ety->semantic(aloc, sc))->isintegral()) + { + sfe->rangefe->lwr->type = indexty; + sfe->rangefe->upr->type = indexty; + IntRange lwrRange = getIntRange(sfe->rangefe->lwr); + IntRange uprRange = getIntRange(sfe->rangefe->upr); + + const dinteger_t lwr = sfe->rangefe->lwr->toInteger(); + dinteger_t upr = sfe->rangefe->upr->toInteger(); + size_t length = 0; + + if (lwrRange.imin <= uprRange.imax) + length = (size_t)(upr - lwr); + + Expressions *exps = new Expressions(); + exps->setDim(length); + + if (sfe->rangefe->op == TOKforeach) + { + for (size_t i = 0; i < length; i++) + (*exps)[i] = new IntegerExp(aloc, lwr + i, indexty); + } + else + { + --upr; + for (size_t i = 0; i < length; i++) + (*exps)[i] = new IntegerExp(aloc, upr - i, indexty); + } + aggr = new ArrayLiteralExp(aloc, indexty->arrayOf(), exps); + } + else + { + aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2)); + sc = sc->startCTFE(); + aggr = semantic(aggr, sc); + aggr = resolveProperties(sc, aggr); + sc = sc->endCTFE(); + aggr = aggr->optimize(WANTvalue); + aggr = aggr->ctfeInterpret(); + } assert(!!sfe->aggrfe ^ !!sfe->rangefe); sfe->aggrfe = new ForeachStatement(sfe->loc, TOKforeach, pparams[2], aggr, -- 2.25.1