Files
ldc/backend/go.c
Alexey Prokhin caad8cde58 Squashed 'dmd2/' content from commit 10017d5
git-subtree-dir: dmd2
git-subtree-split: 10017d50eaaff4ecdc37a0153b6c37ea0b004c81
2012-04-05 11:10:48 +04:00

369 lines
10 KiB
C

// 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#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