From cbbd0e87e4f1907a5c13e922652caf4dcc90fa3e Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Fri, 9 Apr 2021 01:52:28 -0700 Subject: [PATCH] fix Issue 20855 - stack overflow when compiling large file --- src/dmd/backend/backconfig.d | 2 ++ src/dmd/backend/blockopt.d | 8 +++++++- src/dmd/backend/cgcod.d | 5 ++++- src/dmd/backend/go.d | 5 +++-- src/dmd/backend/gother.d | 6 +++--- src/dmd/backend/symbol.d | 12 ++++++++++-- src/dmd/s2ir.d | 5 +++++ test/runnable/test20855.d | 26 ++++++++++++++++++++++++++ 8 files changed, 60 insertions(+), 9 deletions(-) create mode 100644 test/runnable/test20855.d diff --git a/src/dmd/backend/backconfig.d b/src/dmd/backend/backconfig.d index 378ae806a0d7..0e17d5f48ab7 100644 --- a/src/dmd/backend/backconfig.d +++ b/src/dmd/backend/backconfig.d @@ -110,6 +110,8 @@ static if (TARGET_WINDOS) { config.exe = EX_WIN32; config.ehmethod = useExceptions ? EHmethod.EH_WIN32 : EHmethod.EH_NONE; + if (mscoff) + config.flags |= CFGnoebp; // test suite fails without this config.objfmt = mscoff ? OBJ_MSCOFF : OBJ_OMF; if (mscoff) config.flags |= CFGnoebp; // test suite fails without this diff --git a/src/dmd/backend/blockopt.d b/src/dmd/backend/blockopt.d index 7f01561b8b20..86c5ad6da8d2 100644 --- a/src/dmd/backend/blockopt.d +++ b/src/dmd/backend/blockopt.d @@ -660,13 +660,19 @@ void blockopt(int iter) blexit(); if (iter >= 2) brmin(); // minimize branching + version (MARS) + // Switched to one block per Statement, do not undo it + enum merge = false; + else + enum merge = true; + do { compdfo(); /* compute depth first order (DFO) */ elimblks(); /* remove blocks not in DFO */ assert(count < iterationLimit); count++; - } while (mergeblks()); /* merge together blocks */ + } while (merge && mergeblks()); // merge together blocks } while (go.changes); debug if (debugw) diff --git a/src/dmd/backend/cgcod.d b/src/dmd/backend/cgcod.d index 334d4bf45920..bb55cf7a5719 100644 --- a/src/dmd/backend/cgcod.d +++ b/src/dmd/backend/cgcod.d @@ -257,6 +257,8 @@ tryagain: mfuncreg = fregsaved; // so we can see which are used // (bit is cleared each time // we use one) + assert(!(needframe && mfuncreg & mBP)); // needframe needs mBP + for (block* b = startblock; b; b = b.Bnext) { memset(&b.Bregcon,0,b.Bregcon.sizeof); // Clear out values in registers @@ -1016,7 +1018,6 @@ else // we need BP to reset the stack before return // otherwise the return address is lost needframe = 1; - } else if (config.flags & CFGalwaysframe) needframe = 1; @@ -1034,7 +1035,9 @@ else anyiasm || Alloca.size ) + { needframe = 1; + } } if (refparam && (anyiasm || I16)) needframe = 1; diff --git a/src/dmd/backend/go.d b/src/dmd/backend/go.d index bd5ff5f7b7b2..ea0df409a9fe 100644 --- a/src/dmd/backend/go.d +++ b/src/dmd/backend/go.d @@ -288,12 +288,13 @@ else // Each pass through the loop can reduce only one level of comma expression. // The infinite loop check needs to take this into account. // Add 100 just to give optimizer more rope to try to converge. - int iterationLimit = 0; + int iterationLimit = 100; for (block* b = startblock; b; b = b.Bnext) { if (!b.Belem) continue; - int d = el_countCommas(b.Belem) + 100; + ++iterationLimit; + int d = el_countCommas(b.Belem); if (d > iterationLimit) iterationLimit = d; } diff --git a/src/dmd/backend/gother.d b/src/dmd/backend/gother.d index f4abb9798bd8..f677ea7bab4e 100644 --- a/src/dmd/backend/gother.d +++ b/src/dmd/backend/gother.d @@ -1290,7 +1290,7 @@ private bool copyPropWalk(elem *n,vec_t IN) { Symbol *v = n.EV.Vsym; - //printf("Checking copyprop for '%s', ty=x%x\n",v.Sident,n.Ety); + //printf("Checking copyprop for '%s', ty=x%x\n", v.Sident.ptr,n.Ety); symbol_debug(v); const ty = n.Ety; uint sz = tysize(n.Ety); @@ -1309,7 +1309,7 @@ private bool copyPropWalk(elem *n,vec_t IN) csz = cast(uint)type_size(c.ET); assert(cast(int)csz >= 0); - //printf("looking at: ("); WReqn(c); printf("), ty=x%x\n",c.EV.E1.Ety); + //printf(" looking at: ("); WReqn(c); printf("), ty=x%x\n",c.EV.E1.Ety); /* Not only must symbol numbers match, but */ /* offsets too (in case of arrays) and sizes */ /* (in case of unions). */ @@ -1333,7 +1333,7 @@ private bool copyPropWalk(elem *n,vec_t IN) { debug if (debugc) { - printf("Copyprop, from '%s'(%d) to '%s'(%d)\n", + printf("Copyprop, '%s'(%d) replaced with '%s'(%d)\n", (v.Sident[0]) ? cast(char *)v.Sident.ptr : "temp".ptr, cast(int) v.Ssymnum, (f.Sident[0]) ? cast(char *)f.Sident.ptr : "temp".ptr, cast(int) f.Ssymnum); } diff --git a/src/dmd/backend/symbol.d b/src/dmd/backend/symbol.d index b21058ecd60d..d5a509052cd2 100644 --- a/src/dmd/backend/symbol.d +++ b/src/dmd/backend/symbol.d @@ -262,9 +262,17 @@ bool Symbol_isAffected(const ref Symbol s) if (s.Sflags & SFLunambig) return false; - /* If it's immutable, it can't be affected + /* If it's immutable, it can't be affected. + * + * Disable this check because: + * 1. Symbol_isAffected is not used by copyprop() and should be. + * 2. Non-@safe functions can temporarilly cast away immutable. + * 3. Need to add an @safe flag to funcsym_p to enable this. + * 4. Const can be mutated by a separate view. + * Address this in a separate PR. */ - if (s.ty() & (mTYconst | mTYimmutable)) + if (0 && + s.ty() & (mTYconst | mTYimmutable)) { return false; } diff --git a/src/dmd/s2ir.d b/src/dmd/s2ir.d index 42b0f1e78189..e1b0b6c2a224 100644 --- a/src/dmd/s2ir.d +++ b/src/dmd/s2ir.d @@ -764,6 +764,11 @@ private extern (C++) class S2irVisitor : Visitor incUsage(irs, s.loc); block_appendexp(blx.curblock, toElemDtor(s.exp, irs)); + + // goto the next block + block* b = blx.curblock; + block_next(blx, BCgoto, null); + b.appendSucc(blx.curblock); } } diff --git a/test/runnable/test20855.d b/test/runnable/test20855.d new file mode 100644 index 000000000000..8d80f96be927 --- /dev/null +++ b/test/runnable/test20855.d @@ -0,0 +1,26 @@ +// https://issues.dlang.org/show_bug.cgi?id=20855 + +string exp() +{ + string s = "a = b + c * d + a;"; + foreach (i; 0 .. 12) + s = s ~ s; + return s; +} + +int test() +{ + auto a=1, b=2, c=3, d=4; + mixin(exp()); + return a; +} + +import core.stdc.stdio; + +int main() +{ + int a = test(); + printf("a = %d\n", a); + assert(test() == 57345); + return 0; +}