// Copyright (C) 1986-1998 by Symantec // Copyright (C) 2000-2009 by Digital Mars // All Rights Reserved // http://www.digitalmars.com // Written by Walter Bright /* * This source file is made available for personal use * only. The license is in /dmd/src/dmd/backendlicense.txt * or /dm/src/dmd/backendlicense.txt * For any other uses, please contact Digital Mars. */ #if !SPP #include #include #include #include #include "cc.h" #include "global.h" #include "oper.h" #include "el.h" #include "go.h" #include "type.h" static char __file__[] = __FILE__; /* for tassert.h */ #include "tassert.h" /**************************** * Terminate use of globals. */ void go_term() { vec_free(defkill); vec_free(starkill); vec_free(vptrkill); util_free(expnod); util_free(expblk); util_free(defnod); } #if DEBUG // to print progress message and current trees set to // DEBUG_TREES to 1 and uncomment next 2 lines #define DEBUG_TREES 0 #if DEBUG_TREES void dbg_optprint(char *); #else // to print progress message, undo comment #define dbg_optprint(c) // dbg_printf(c) #endif #else #define dbg_optprint(c) #endif /************************************** * Parse optimizer command line flag. * Input: * cp flag string * Returns: * 0 not recognized * !=0 recognized */ int go_flag(char *cp) { unsigned i; unsigned flag; enum GL // indices of various flags in flagtab[] { GLO,GLall,GLcnp,GLcp,GLcse,GLda,GLdc,GLdv,GLli,GLliv,GLlocal,GLloop, GLnone,GLo,GLreg,GLspace,GLspeed,GLtime,GLtree,GLvbe,GLMAX }; static const char *flagtab[] = { "O","all","cnp","cp","cse","da","dc","dv","li","liv","local","loop", "none","o","reg","space","speed","time","tree","vbe" }; static mftype flagmftab[] = { 0,MFall,MFcnp,MFcp,MFcse,MFda,MFdc,MFdv,MFli,MFliv,MFlocal,MFloop, 0,0,MFreg,0,MFtime,MFtime,MFtree,MFvbe }; i = GLMAX; assert(i == arraysize(flagtab)); assert(i == arraysize(flagmftab)); //printf("go_flag('%s')\n", cp); flag = binary(cp + 1,flagtab,GLMAX); if (mfoptim == 0 && flag != -1) mfoptim = MFall & ~MFvbe; if (*cp == '-') /* a regular -whatever flag */ { /* cp -> flag string */ switch (flag) { case GLall: case GLcnp: case GLcp: case GLdc: case GLda: case GLdv: case GLcse: case GLli: case GLliv: case GLlocal: case GLloop: case GLreg: case GLspeed: case GLtime: case GLtree: case GLvbe: mfoptim &= ~flagmftab[flag]; /* clear bits */ break; case GLo: case GLO: case GLnone: mfoptim |= MFall & ~MFvbe; // inverse of -all break; case GLspace: mfoptim |= MFtime; /* inverse of -time */ break; case -1: /* not in flagtab[] */ goto badflag; default: assert(0); } } else if (*cp == '+') /* a regular +whatever flag */ { /* cp -> flag string */ switch (flag) { case GLall: case GLcnp: case GLcp: case GLdc: case GLda: case GLdv: case GLcse: case GLli: case GLliv: case GLlocal: case GLloop: case GLreg: case GLspeed: case GLtime: case GLtree: case GLvbe: mfoptim |= flagmftab[flag]; /* set bits */ break; case GLnone: mfoptim &= ~MFall; /* inverse of +all */ break; case GLspace: mfoptim &= ~MFtime; /* inverse of +time */ break; case -1: /* not in flagtab[] */ goto badflag; default: assert(0); } } if (mfoptim) { mfoptim |= MFtree | MFdc; // always do at least this much config.flags4 |= (mfoptim & MFtime) ? CFG4speed : CFG4space; } else { config.flags4 &= ~CFG4optimized; } return 1; // recognized badflag: return 0; } #if DEBUG_TREES void dbg_optprint(char *title) { block *b; for (b = startblock; b; b = b->Bnext) if (b->Belem) { dbg_printf("%s\n",title); elem_print(b->Belem); } } #endif /**************************** * Optimize function. */ void optfunc() { #if !HTOD block *b; int iter; // iteration count clock_t starttime; cmes ("optfunc()\n"); dbg_optprint("optfunc\n"); #ifdef DEBUG if (debugb) { dbg_printf("................Before optimization.........\n"); WRfunc(); } #endif iter = 0; if (localgot) { // Initialize with: // localgot = OPgot; elem *e = el_long(TYnptr, 0); e->Eoper = OPgot; e = el_bin(OPeq, TYnptr, el_var(localgot), e); startblock->Belem = el_combine(e, startblock->Belem); } // Each pass through the loop can reduce only one level of comma expression. // The infinite loop check needs to take this into account. int iterationLimit = 0; for (b = startblock; b; b = b->Bnext) { if (!b->Belem) continue; int d = el_countCommas(b->Belem); if (d > iterationLimit) iterationLimit = d; } // Some functions can take enormous amounts of time to optimize. // We try to put a lid on it. starttime = clock(); do { //printf("iter = %d\n", iter); if (++iter > 200) { assert(iter < iterationLimit); // infinite loop check break; } #if MARS util_progress(); #else file_progress(); #endif //printf("optelem\n"); /* canonicalize the trees */ for (b = startblock; b; b = b->Bnext) if (b->Belem) { #if DEBUG if(debuge) { dbg_printf("before\n"); elem_print(b->Belem); //el_check(b->Belem); } #endif b->Belem = doptelem(b->Belem,bc_goal[b->BC] | GOALagain); #if DEBUG if(0 && debugf) { dbg_printf("after\n"); elem_print(b->Belem); } #endif } //printf("blockopt\n"); if (mfoptim & MFdc) blockopt(0); // do block optimization out_regcand(&globsym); // recompute register candidates changes = 0; /* no changes yet */ if (mfoptim & MFcnp) constprop(); /* make relationals unsigned */ if (mfoptim & (MFli | MFliv)) loopopt(); /* remove loop invariants and */ /* induction vars */ /* do loop rotation */ else for (b = startblock; b; b = b->Bnext) b->Bweight = 1; dbg_optprint("boolopt\n"); if (mfoptim & MFcnp) boolopt(); // optimize boolean values if (changes && mfoptim & MFloop && (clock() - starttime) < 30 * CLOCKS_PER_SEC) continue; if (mfoptim & MFcnp) constprop(); /* constant propagation */ if (mfoptim & MFcp) copyprop(); /* do copy propagation */ /* Floating point constants and string literals need to be * replaced with loads from variables in read-only data. * This can result in localgot getting needed. */ symbol *localgotsave = localgot; for (b = startblock; b; b = b->Bnext) { if (b->Belem) { b->Belem = doptelem(b->Belem,bc_goal[b->BC] | GOALstruct); if (b->Belem) b->Belem = el_convert(b->Belem); } } if (localgot != localgotsave) { /* Looks like we did need localgot, initialize with: * localgot = OPgot; */ elem *e = el_long(TYnptr, 0); e->Eoper = OPgot; e = el_bin(OPeq, TYnptr, el_var(localgot), e); startblock->Belem = el_combine(e, startblock->Belem); } /* localize() is after localgot, otherwise we wind up with * more than one OPgot in a function, which mucks up OSX * code generation which assumes at most one (localgotoffset). */ if (mfoptim & MFlocal) localize(); // improve expression locality if (mfoptim & MFda) rmdeadass(); /* remove dead assignments */ cmes2 ("changes = %d\n", changes); if (!(changes && mfoptim & MFloop && (clock() - starttime) < 30 * CLOCKS_PER_SEC)) break; } while (1); cmes2("%d iterations\n",iter); if (mfoptim & MFdc) blockopt(1); // do block optimization for (b = startblock; b; b = b->Bnext) { if (b->Belem) postoptelem(b->Belem); } if (mfoptim & MFvbe) verybusyexp(); /* very busy expressions */ if (mfoptim & MFcse) builddags(); /* common subexpressions */ if (mfoptim & MFdv) deadvar(); /* eliminate dead variables */ #ifdef DEBUG if (debugb) { dbg_printf(".............After optimization...........\n"); WRfunc(); } #endif // Prepare for code generator for (b = startblock; b; b = b->Bnext) { block_optimizer_free(b); } #endif } #endif // !SPP