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

Reply via email to