Files
ldc/backend/blockopt.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

2205 lines
63 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright (C) 1986-1997 by Symantec
// Copyright (C) 2000-2010 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.
*/
/****************************************************************
* Handle basic blocks.
*/
#if !SPP
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include "cc.h"
#include "oper.h"
#include "el.h"
#include "type.h"
#include "global.h"
#include "go.h"
#include "code.h"
#if SCPP
#include "parser.h"
#include "iasm.h"
#endif
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"
STATIC void bropt(void);
STATIC void brrear(void);
STATIC void search(block *b);
STATIC void elimblks(void);
STATIC int mergeblks(void);
STATIC void blident(void);
STATIC void blreturn(void);
STATIC void brmin(void);
STATIC void bltailmerge(void);
STATIC void block_check();
STATIC void brtailrecursion();
STATIC elem * assignparams(elem **pe,int *psi,elem **pe2);
STATIC void emptyloops();
int el_anyframeptr(elem *e);
unsigned numblks; // number of basic blocks in current function
block *startblock; /* beginning block of function */
/* (can have no predecessors) */
block **dfo = NULL; /* array of depth first order */
unsigned dfotop; /* # of items in dfo[] */
block *curblock; /* current block being read in */
block *block_last; // last block read in
static block * block_freelist;
////////////////////////////
// Storage allocator.
static block blkzero;
__inline block *block_calloc_i()
{ block *b;
if (block_freelist)
{ b = block_freelist;
block_freelist = b->Bnext;
*b = blkzero;
}
else
b = (block *) mem_fcalloc(sizeof(block));
return b;
}
block *block_calloc()
{
return block_calloc_i();
}
//////////////////////////////////
//
unsigned bc_goal[BCMAX];
void block_init()
{ int i;
for (i = 0; i < BCMAX; i++)
bc_goal[i] = GOALvalue;
bc_goal[BCgoto] = GOALnone;
bc_goal[BCret ] = GOALnone;
bc_goal[BCexit] = GOALnone;
}
//////////////////////////////////
//
void block_term()
{
#if TERMCODE
block *b;
while (block_freelist)
{ b = block_freelist->Bnext;
mem_ffree(block_freelist);
block_freelist = b;
}
#endif
}
/**************************
* Finish up this block and start the next one.
*/
#if MARS
void block_next(Blockx *bctx,enum BC bc,block *bn)
{
bctx->curblock->BC = bc;
block_last = bctx->curblock;
if (!bn)
bn = block_calloc_i();
bctx->curblock->Bnext = bn; // next block
bctx->curblock = bctx->curblock->Bnext; // new current block
#if NTEXCEPTIONS
bctx->curblock->Btry = bctx->tryblock;
#endif
bctx->curblock->Bflags |= bctx->flags;
}
#else
void block_next(enum BC bc,block *bn)
{
curblock->BC = bc;
curblock->Bsymend = globsym.top;
block_last = curblock;
if (!bn)
bn = block_calloc_i();
curblock->Bnext = bn; // next block
curblock = curblock->Bnext; // new current block
curblock->Bsymstart = globsym.top;
curblock->Btry = pstate.STbtry;
}
void block_next()
{
block_next((enum BC)curblock->BC,NULL);
}
#endif
/**************************
* Finish up this block and start the next one.
*/
#if MARS
block *block_goto(Blockx *bx,enum BC bc,block *bn)
{ block *b;
b = bx->curblock;
block_next(bx,bc,bn);
list_append(&b->Bsucc,bx->curblock);
return bx->curblock;
}
#endif
/****************************
* Goto a block named gotolbl.
* Start a new block that is labelled by newlbl.
*/
#if SCPP
void block_goto()
{
block_goto(block_calloc());
}
void block_goto(block *bn)
{
block_goto(bn,bn);
}
void block_goto(block *bgoto,block *bnew)
{
enum BC bc;
assert(bgoto);
list_append(&(curblock->Bsucc),bgoto);
if (curblock->Bcode) // If there is already code in the block
// then this is an ASM block
bc = BCasm;
else
bc = BCgoto; // fall thru to next block
block_next(bc,bnew);
}
#endif
/**********************************
* Replace block numbers with block pointers.
* Also compute numblks and maxblks.
*/
void block_ptr()
{ block *b;
/* dbg_printf("block_ptr()\n");*/
numblks = 0;
for (b = startblock; b; b = b->Bnext) /* for each block */
{
#if SCPP
b->Bblknum = numblks;
#endif
numblks++;
}
maxblks = 3 * numblks; /* allow for increase in # of blocks */
}
/*******************************
* Build predecessor list (Bpred) for each block.
*/
void block_pred()
{ block *b;
//dbg_printf("block_pred()\n");
for (b = startblock; b; b = b->Bnext) /* for each block */
list_free(&b->Bpred,FPNULL);
for (b = startblock; b; b = b->Bnext) /* for each block */
{ register list_t bp;
//printf("b = %p, BC = ",b); WRBC(b->BC); printf("\n");
for (bp = b->Bsucc; bp; bp = list_next(bp))
{ /* for each successor to b */
//printf("\tbs = %p\n",list_block(bp));
assert(list_block(bp));
list_prepend(&(list_block(bp)->Bpred),b);
}
}
assert(startblock->Bpred == NULL); /* startblock has no preds */
}
/********************************************
* Clear visit.
*/
void block_clearvisit()
{ block *b;
for (b = startblock; b; b = b->Bnext) // for each block
b->Bflags &= ~BFLvisited; // mark as unvisited
}
/********************************************
* Visit block and each of its predecessors.
*/
void block_visit(block *b)
{ list_t l;
b->Bflags |= BFLvisited;
for (l = b->Bsucc; l; l = list_next(l)) // for each successor
{ block *bs = list_block(l);
assert(bs);
if ((bs->Bflags & BFLvisited) == 0) // if not visited
block_visit(bs);
}
}
/*****************************
* Compute number of parents (Bcount) of each basic block.
*/
void block_compbcount()
{
block_clearvisit();
block_visit(startblock); // visit all reachable blocks
elimblks(); // eliminate unvisited blocks
}
/*******************************
* Free list of blocks.
*/
void blocklist_free(block **pb)
{ block *b,*bn;
for (b = *pb; b; b = bn)
{ bn = b->Bnext;
block_free(b);
}
*pb = NULL;
}
/********************************
* Free optimizer gathered data.
*/
void block_optimizer_free(block *b)
{
vec_free(b->Bdom);
vec_free(b->Binrd);
vec_free(b->Boutrd);
vec_free(b->Binlv);
vec_free(b->Boutlv);
vec_free(b->Bin);
vec_free(b->Bout);
vec_free(b->Bgen);
vec_free(b->Bkill);
vec_free(b->Bout2);
vec_free(b->Bgen2);
vec_free(b->Bkill2);
memset(&b->_BLU,0,sizeof(b->_BLU));
}
/****************************
* Free a block.
*/
void block_free(block *b)
{
assert(b);
if (b->Belem)
el_free(b->Belem);
list_free(&b->Bsucc,FPNULL);
list_free(&b->Bpred,FPNULL);
if (OPTIMIZER)
block_optimizer_free(b);
switch (b->BC)
{ case BCswitch:
case BCifthen:
case BCjmptab:
#if MARS
free(b->BS.Bswitch);
#else
MEM_PH_FREE(b->BS.Bswitch);
#endif
break;
#if SCPP
case BCcatch:
type_free(b->Bcatchtype);
break;
#endif
case BCasm:
code_free(b->Bcode);
break;
}
b->Bnext = block_freelist;
block_freelist = b;
}
/****************************
* Hydrate/dehydrate a list of blocks.
*/
#if HYDRATE
void blocklist_hydrate(block **pb)
{ block *b;
while (isdehydrated(*pb))
{
/*dbg_printf("blocklist_hydrate(*pb = %p) =",*pb);*/
b = (block *)ph_hydrate(pb);
/*dbg_printf(" %p\n",b);*/
el_hydrate(&b->Belem);
list_hydrate(&b->Bsucc,FPNULL);
list_hydrate(&b->Bpred,FPNULL);
(void) ph_hydrate(&b->Btry);
#if SCPP
(void) ph_hydrate(&b->Bendscope);
symbol_hydrate(&b->Binitvar);
#endif
switch (b->BC)
{
#if SCPP
case BCtry:
symbol_hydrate(&b->catchvar);
break;
case BCcatch:
type_hydrate(&b->Bcatchtype);
break;
#endif
case BCswitch:
(void) ph_hydrate(&b->BS.Bswitch);
break;
case BC_finally:
//(void) ph_hydrate(&b->B_ret);
break;
case BCasm:
code_hydrate(&b->Bcode);
break;
}
#if TX86
filename_translate(&b->Bsrcpos);
srcpos_hydrate(&b->Bsrcpos);
#endif
pb = &b->Bnext;
}
}
#endif
#if DEHYDRATE
void blocklist_dehydrate(block **pb)
{ block *b;
while ((b = *pb) != NULL && !isdehydrated(b))
{
#if DEBUG_XSYMGEN
if (xsym_gen && ph_in_head(b))
return;
#endif
/*dbg_printf("blocklist_dehydrate(*pb = %p) =",b);*/
ph_dehydrate(pb);
/*dbg_printf(" %p\n",*pb);*/
el_dehydrate(&b->Belem);
list_dehydrate(&b->Bsucc,FPNULL);
list_dehydrate(&b->Bpred,FPNULL);
ph_dehydrate(&b->Btry);
#if SCPP
ph_dehydrate(&b->Bendscope);
symbol_dehydrate(&b->Binitvar);
#endif
switch (b->BC)
{
#if SCPP
case BCtry:
symbol_dehydrate(&b->catchvar);
break;
case BCcatch:
type_dehydrate(&b->Bcatchtype);
break;
#endif
case BCswitch:
ph_dehydrate(&b->BS.Bswitch);
break;
case BC_finally:
//ph_dehydrate(&b->B_ret);
break;
case BCasm:
code_dehydrate(&b->Bcode);
break;
}
#if TX86
srcpos_dehydrate(&b->Bsrcpos);
#endif
pb = &b->Bnext;
}
}
#endif
/****************************
* Append elem to the elems comprising the current block.
* Read in an expression and put it in curblock->Belem.
* If there is one already there, create a tree like:
* ,
* / \
* old e
*/
void block_appendexp(block *b,elem *e)
{ elem *ec;
elem **pe;
assert(MARS || PARSER);
if (e)
{
assert(b);
elem_debug(e);
pe = &b->Belem;
ec = *pe;
if (ec != NULL)
{
type *t = e->ET;
if (t)
type_debug(t);
elem_debug(e);
#if MARS
tym_t ty = e->Ety;
elem_debug(e);
/* Build tree such that (a,b) => (a,(b,e)) */
while (ec->Eoper == OPcomma)
{
ec->Ety = ty;
ec->ET = t;
pe = &(ec->E2);
ec = *pe;
}
e = el_bin(OPcomma,ty,ec,e);
e->ET = t;
#else
/* Build tree such that (a,b) => (a,(b,e)) */
while (ec->Eoper == OPcomma)
{
el_settype(ec,t);
pe = &(ec->E2);
ec = *pe;
}
e = el_bint(OPcomma,t,ec,e);
#endif
}
*pe = e;
}
}
/************************
* Mark curblock as initializing symbol s.
*/
#if SCPP
#undef block_initvar
void block_initvar(symbol *s)
{
#ifdef DEBUG
assert(curblock);
#endif
symbol_debug(s);
curblock->Binitvar = s;
}
#endif
/*******************
* Mark end of function.
* flag:
* 0 do a "return"
* 1 do a "return 0"
*/
void block_endfunc(int flag)
{
#if SCPP
curblock->Bsymend = globsym.top;
curblock->Bendscope = curblock;
#endif
if (flag)
{ elem *e;
e = el_longt(tsint, 0);
block_appendexp(curblock, e);
curblock->BC = BCretexp; // put a return at the end
}
else
curblock->BC = BCret; // put a return at the end
curblock = NULL; // undefined from now on
block_last = NULL;
}
/******************************
* Perform branch optimization on basic blocks.
*/
void blockopt(int iter)
{ block *b;
int count;
if (OPTIMIZER)
{
int iterationLimit = 200;
if (iterationLimit < numblks)
iterationLimit = numblks;
count = 0;
do
{
//printf("changes = %d, count = %d, dfotop = %d\n",changes,count,dfotop);
#if MARS
util_progress();
#else
if (controlc_saw)
util_exit(EXIT_BREAK);
#endif
changes = 0;
bropt(); // branch optimization
brrear(); // branch rearrangement
blident(); // combine identical blocks
blreturn(); // split out return blocks
bltailmerge(); // do tail merging
brtailrecursion(); // do tail recursion
brcombine(); // convert graph to expressions
if (iter >= 2)
brmin(); // minimize branching
do
{
compdfo(); /* compute depth first order (DFO) */
elimblks(); /* remove blocks not in DFO */
assert(count < iterationLimit);
count++;
} while (mergeblks()); /* merge together blocks */
} while (changes);
#ifdef DEBUG
if (debugw)
for (b = startblock; b; b = b->Bnext)
WRblock(b);
#endif
}
else
{
/* canonicalize the trees */
for (b = startblock; b; b = b->Bnext)
{
#ifdef DEBUG
if (debugb)
WRblock(b);
#endif
if (b->Belem)
{ b->Belem = doptelem(b->Belem,bc_goal[b->BC] | GOALstruct);
if (b->Belem)
b->Belem = el_convert(b->Belem);
}
#ifdef DEBUG
if (debugb)
{ dbg_printf("after optelem():\n");
WRblock(b);
}
#endif
}
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);
}
bropt(); /* branch optimization */
brrear(); /* branch rearrangement */
comsubs(); /* eliminate common subexpressions */
#ifdef DEBUG
if (debugb)
for (b = startblock; b; b = b->Bnext)
WRblock(b);
#endif
}
}
/***********************************
* Try to remove control structure.
* That is, try to resolve if-else, goto and return statements
* into &&, || and ?: combinations.
*/
void brcombine()
{ block *b;
block *b2,*b3;
int op;
int anychanges;
cmes("brcombine()\n");
//for (b = startblock; b; b = b->Bnext)
//WRblock(b);
if (funcsym_p->Sfunc->Fflags3 & (Fcppeh | Fnteh))
{ // Don't mess up extra EH info by eliminating blocks
return;
}
do
{
anychanges = 0;
for (b = startblock; b; b = b->Bnext) /* for each block */
{ unsigned char bc;
/* Look for [e1 IFFALSE L3,L2] L2: [e2 GOTO L3] L3: [e3] */
/* Replace with [(e1 && e2),e3] */
bc = b->BC;
if (bc == BCiftrue)
{ unsigned char bc2;
b2 = list_block(b->Bsucc);
b3 = list_block(list_next(b->Bsucc));
if (list_next(b2->Bpred)) // if more than one predecessor
continue;
if (b2 == b3)
continue;
if (b2 == startblock)
continue;
if (!PARSER && b2->Belem && EOP(b2->Belem))
continue;
bc2 = b2->BC;
if (bc2 == BCgoto &&
b3 == list_block(b2->Bsucc))
{
b->BC = BCgoto;
if (b2->Belem)
{
op = OPandand;
b->Belem = PARSER ? el_bint(op,tsint,b->Belem,b2->Belem)
: el_bin(op,TYint,b->Belem,b2->Belem);
b2->Belem = NULL;
}
list_subtract(&(b->Bsucc),b2);
list_subtract(&(b2->Bpred),b);
cmes("brcombine(): if !e1 then e2 => e1 || e2\n");
anychanges++;
}
else if (list_next(b3->Bpred) || b3 == startblock)
continue;
else if ((bc2 == BCretexp && b3->BC == BCretexp)
//|| (bc2 == BCret && b3->BC == BCret)
)
{ elem *e;
if (PARSER)
{
type *t = (bc2 == BCretexp) ? b2->Belem->ET : tsvoid;
e = el_bint(OPcolon2,t,b2->Belem,b3->Belem);
b->Belem = el_bint(OPcond,t,b->Belem,e);
}
else
{
if (EOP(b3->Belem))
continue;
tym_t ty = (bc2 == BCretexp) ? b2->Belem->Ety : TYvoid;
e = el_bin(OPcolon2,ty,b2->Belem,b3->Belem);
b->Belem = el_bin(OPcond,ty,b->Belem,e);
}
b->BC = bc2;
b->Belem->ET = b2->Belem->ET;
b2->Belem = NULL;
b3->Belem = NULL;
list_free(&b->Bsucc,FPNULL);
list_subtract(&(b2->Bpred),b);
list_subtract(&(b3->Bpred),b);
cmes("brcombine(): if e1 return e2 else return e3 => ret e1?e2:e3\n");
anychanges++;
}
else if (bc2 == BCgoto &&
b3->BC == BCgoto &&
list_block(b2->Bsucc) == list_block(b3->Bsucc))
{ elem *e;
block *bsucc;
bsucc = list_block(b2->Bsucc);
if (b2->Belem)
{
if (PARSER)
{
if (b3->Belem)
{
e = el_bint(OPcolon2,b2->Belem->ET,
b2->Belem,b3->Belem);
e = el_bint(OPcond,e->ET,b->Belem,e);
}
else
{
op = OPandand;
e = el_bint(op,tsint,b->Belem,b2->Belem);
}
}
else
{
if (b3->Belem)
{
if (EOP(b3->Belem))
continue;
e = el_bin(OPcolon2,b2->Belem->Ety,
b2->Belem,b3->Belem);
e = el_bin(OPcond,e->Ety,b->Belem,e);
e->ET = b2->Belem->ET;
}
else
{
op = OPandand;
e = el_bin(op,TYint,b->Belem,b2->Belem);
}
}
b2->Belem = NULL;
b->Belem = e;
}
else if (b3->Belem)
{
op = OPoror;
b->Belem = PARSER ? el_bint(op,tsint,b->Belem,b3->Belem)
: el_bin(op,TYint,b->Belem,b3->Belem);
}
b->BC = BCgoto;
b3->Belem = NULL;
list_free(&b->Bsucc,FPNULL);
list_append(&b->Bsucc,bsucc);
list_append(&bsucc->Bpred,b);
list_free(&(b2->Bpred),FPNULL);
list_free(&(b2->Bsucc),FPNULL);
list_free(&(b3->Bpred),FPNULL);
list_free(&(b3->Bsucc),FPNULL);
b2->BC = BCret;
b3->BC = BCret;
list_subtract(&(bsucc->Bpred),b2);
list_subtract(&(bsucc->Bpred),b3);
cmes("brcombine(): if e1 goto e2 else goto e3 => ret e1?e2:e3\n");
anychanges++;
}
}
else if (bc == BCgoto && PARSER)
{
b2 = list_block(b->Bsucc);
if (!list_next(b2->Bpred) && b2->BC != BCasm // if b is only parent
&& b2 != startblock
#if SCPP
&& b2->BC != BCtry
#endif
&& b2->BC != BC_try
&& b->Btry == b2->Btry
)
{ list_t bl;
if (b2->Belem)
{
if (PARSER)
{
block_appendexp(b,b2->Belem);
}
else if (b->Belem)
b->Belem = el_bin(OPcomma,b2->Belem->Ety,b->Belem,b2->Belem);
else
b->Belem = b2->Belem;
b2->Belem = NULL;
}
list_subtract(&b->Bsucc,b2);
list_subtract(&b2->Bpred,b);
/* change predecessor of successors of b2 from b2 to b */
for (bl = b2->Bsucc; bl; bl = list_next(bl))
{ list_t bp;
for (bp = list_block(bl)->Bpred; bp; bp = list_next(bp))
{
if (list_block(bp) == b2)
list_ptr(bp) = (void *)b;
}
}
b->BC = b2->BC;
b->BS = b2->BS;
b->Bsucc = b2->Bsucc;
b2->Bsucc = NULL;
b2->BC = BCret; /* a harmless one */
cmes3("brcombine(): %p goto %p eliminated\n",b,b2);
anychanges++;
}
}
}
if (anychanges)
{ changes++;
continue;
}
} while (0);
}
/***********************
* Branch optimization.
*/
STATIC void bropt()
{ block *b,*db;
elem *n,**pn;
cmes("bropt()\n");
assert(!PARSER);
for (b = startblock; b; b = b->Bnext) /* for each block */
{
pn = &(b->Belem);
if (OPTIMIZER && *pn)
while ((*pn)->Eoper == OPcomma)
pn = &((*pn)->E2);
n = *pn;
if (b->BC == BCiftrue)
{
assert(n);
/* Replace IF (!e) GOTO ... with */
/* IF OPnot (e) GOTO ... */
if (n->Eoper == OPnot)
{
tym_t tym;
tym = n->E1->Ety;
*pn = el_selecte1(n);
(*pn)->Ety = tym;
for (n = b->Belem; n->Eoper == OPcomma; n = n->E2)
n->Ety = tym;
b->Bsucc = list_reverse(b->Bsucc);
cmes("CHANGE: if (!e)\n");
changes++;
}
/* Take care of IF (constant) */
if (iftrue(n)) /* if elem is TRUE */
{
// select first succ
db = list_block(list_next(b->Bsucc));
goto L1;
}
else if (iffalse(n))
{
// select second succ
db = list_block(b->Bsucc);
L1: list_subtract(&(b->Bsucc),db);
list_subtract(&(db->Bpred),b);
b->BC = BCgoto;
/* delete elem if it has no side effects */
b->Belem = doptelem(b->Belem,GOALnone | GOALagain);
cmes("CHANGE: if (const)\n");
changes++;
}
/* Look for both destinations being the same */
else if (list_block(b->Bsucc) ==
list_block(list_next(b->Bsucc)))
{ b->BC = BCgoto;
db = list_block(b->Bsucc);
list_subtract(&(b->Bsucc),db);
list_subtract(&(db->Bpred),b);
cmes("CHANGE: if (e) goto L1; else goto L1;\n");
changes++;
}
}
else if (b->BC == BCswitch)
{ /* see we can evaluate this switch now */
register unsigned i,ncases;
targ_llong *p,value;
register list_t bl;
while (n->Eoper == OPcomma)
n = n->E2;
if (n->Eoper != OPconst)
continue;
assert(tyintegral(n->Ety));
value = el_tolong(n);
p = b->BS.Bswitch; /* ptr to switch data */
assert(p);
ncases = *p++; /* # of cases */
i = 1; /* first case */
while (1)
{
if (i > ncases)
{ i = 0; /* select default */
break;
}
if (*p++ == value)
break; /* found it */
i++; /* next case */
}
/* the ith entry in Bsucc is the one we want */
db = list_block(list_nth(b->Bsucc,i));
/* delete predecessors of successors (!) */
for (bl = b->Bsucc; bl; bl = list_next(bl))
if (i--) // if not ith successor
{ void *p;
p = list_subtract(
&(list_block(bl)->Bpred),b);
assert(p == b);
}
/* dump old successor list and create a new one */
list_free(&b->Bsucc,FPNULL);
list_append(&b->Bsucc,db);
b->BC = BCgoto;
b->Belem = doptelem(b->Belem,GOALnone | GOALagain);
cmes("CHANGE: switch (const)\n");
changes++;
}
}
}
/*********************************
* Do branch rearrangement.
*/
STATIC void brrear()
{ register block *b;
cmes("brrear()\n");
for (b = startblock; b; b = b->Bnext) /* for each block */
{ register list_t bl;
for (bl = b->Bsucc; bl; bl = list_next(bl))
{ /* For each transfer of control block pointer */
block *bt;
int iter = 0;
bt = list_block(bl);
/* If it is a transfer to a block that consists */
/* of nothing but an unconditional transfer, */
/* Replace transfer address with that */
/* transfer address. */
/* Note: There are certain kinds of infinite */
/* loops which we avoid by putting a lid on */
/* the number of iterations. */
while (bt->BC == BCgoto && !bt->Belem &&
#if SCPP || NTEXCEPTIONS
b->Btry == bt->Btry &&
#endif
#if NTEXCEPTIONS
bt->Btry == list_block(bt->Bsucc)->Btry &&
#endif
++iter < 10)
{
list_ptr(bl) = list_ptr(bt->Bsucc);
if (bt->Bsrcpos.Slinnum && !b->Bsrcpos.Slinnum)
b->Bsrcpos = bt->Bsrcpos;
b->Bflags |= bt->Bflags;
list_append(&(list_block(bl)->Bpred),b);
list_subtract(&(bt->Bpred),b);
cmes("goto->goto\n");
bt = list_block(bl);
}
// Bsucc after the first are the targets of
// jumps, calls and loops, and as such to do this right
// we need to traverse the Bcode list and fix up
// the IEV2.Vblock pointers.
if (b->BC == BCasm)
break;
}
#if 0
/* Replace cases of */
/* IF (e) GOTO L1 ELSE L2 */
/* L1: */
/* with */
/* IF OPnot (e) GOTO L2 ELSE L1 */
/* L1: */
if (b->BC == BCiftrue || b->BC == BCiffalse)
{ register block *bif,*belse;
bif = list_block(b->Bsucc);
belse = list_block(list_next(b->Bsucc));
if (bif == b->Bnext)
{ b->BC ^= BCiffalse ^ BCiftrue; /* toggle */
list_ptr(b->Bsucc) = belse;
list_ptr(list_next(b->Bsucc)) = bif;
b->Bflags |= bif->Bflags & BFLvisited;
cmes("if (e) L1 else L2\n");
}
}
#endif
} /* for */
}
/*************************
* Compute depth first order (DFO).
* Equivalent to Aho & Ullman Fig. 13.8.
* Blocks not in dfo[] are unreachable.
*/
void compdfo()
{
register int i;
cmes("compdfo()\n");
assert(OPTIMIZER);
block_clearvisit();
#ifdef DEBUG
if (maxblks == 0 || maxblks < numblks)
dbg_printf("maxblks = %d, numblks = %d\n",maxblks,numblks);
#endif
assert(maxblks && maxblks >= numblks);
debug_assert(!PARSER);
if (!dfo)
#if TX86
dfo = (block **) util_calloc(sizeof(block *),maxblks);
#else
dfo = (block **) MEM_PARF_CALLOC(sizeof(block *) * maxblks);
#endif
dfotop = numblks; /* assign numbers backwards */
search(startblock);
assert(dfotop <= numblks);
/* Ripple data to the bottom of the array */
if (dfotop) /* if not at bottom */
{ for (i = 0; i < numblks - dfotop; i++)
{ dfo[i] = dfo[i + dfotop];
dfo[i]->Bdfoidx = i;
}
}
dfotop = numblks - dfotop;
#if 0
for (i = 0; i < dfotop; i++)
dbg_printf("dfo[%d] = 0x%x\n",i,dfo[i]);
#endif
}
/******************************
* Add block to dfo[], then its successors.
*/
STATIC void search(block *b)
{ list_t l;
assert(b);
b->Bflags |= BFLvisited; // executed at least once
for (l = b->Bsucc; l; l = list_next(l)) // for each successor
{ block *bs = list_block(l);
assert(bs);
if ((bs->Bflags & BFLvisited) == 0) // if not visited
search(bs); // search it
}
dfo[--dfotop] = b; // add to dfo[]
b->Bdfoidx = dfotop; // link back
}
/*************************
* Remove blocks not marked as visited (they aren't in dfo[]).
* A block is not in dfo[] if not visited.
*/
STATIC void elimblks()
{ block **pb,*b;
list_t s;
block *bf;
#ifdef DEBUG
if (OPTIMIZER)
{ int n;
n = 0;
for (b = startblock; b; b = b->Bnext)
n++;
//dbg_printf("1 n = %d, numblks = %d, dfotop = %d\n",n,numblks,dfotop);
assert(numblks == n);
}
#endif
cmes("elimblks()\n");
bf = NULL;
for (pb = &startblock; (b = *pb) != NULL;)
{
if (((b->Bflags & BFLvisited) == 0) /* if block is not visited */
&& ((b->Bflags & BFLlabel) == 0) /* need label offset */
)
{
/* for each marked successor S to b */
/* remove b from S.Bpred. */
/* Presumably all predecessors to b are unmarked also. */
for (s = b->Bsucc; s; s = list_next(s))
{ assert(list_block(s));
if (list_block(s)->Bflags & BFLvisited) /* if it is marked */
list_subtract(&(list_block(s)->Bpred),b);
}
if (b->Balign && b->Bnext && b->Balign > b->Bnext->Balign)
b->Bnext->Balign = b->Balign;
*pb = b->Bnext; /* remove from linked list */
b->Bnext = bf;
bf = b; /* prepend to deferred list to free */
cmes2("CHANGE: block %p deleted\n",b);
changes++;
}
else
pb = &((*pb)->Bnext);
}
// Do deferred free's of the blocks
for ( ; bf; bf = b)
{ b = bf->Bnext;
block_free(bf);
numblks--;
}
cmes("elimblks done\n");
assert(!OPTIMIZER || numblks == dfotop);
}
/**********************************
* Merge together blocks where the first block is a goto to the next
* block and the next block has only the first block as a predecessor.
* Example:
* e1; GOTO L2;
* L2: return e2;
* becomes:
* L2: return (e1 , e2);
* Returns:
* # of merged blocks
*/
STATIC int mergeblks()
{ int merge = 0,i;
assert(OPTIMIZER);
cmes("mergeblks()\n");
for (i = 0; i < dfotop; i++)
{ block *b;
b = dfo[i];
if (b->BC == BCgoto)
{ block *bL2 = list_block(b->Bsucc);
if (b == bL2)
{
Lcontinue:
continue;
}
assert(bL2->Bpred);
if (!list_next(bL2->Bpred) && bL2 != startblock)
{ list_t bl;
elem *e;
if (b == bL2 || bL2->BC == BCasm)
continue;
if (
#if SCPP
bL2->BC == BCtry ||
#endif
bL2->BC == BC_try ||
b->Btry != bL2->Btry)
continue;
#if SCPP
// If any predecessors of b are BCasm, don't merge.
for (bl = b->Bpred; bl; bl = list_next(bl))
{
if (list_block(bl)->BC == BCasm)
goto Lcontinue;
}
#endif
/* JOIN the elems */
e = el_combine(b->Belem,bL2->Belem);
if (b->Belem && bL2->Belem)
e = doptelem(e,bc_goal[bL2->BC] | GOALagain);
bL2->Belem = e;
b->Belem = NULL;
/* Remove b from predecessors of bL2 */
list_free(&(bL2->Bpred),FPNULL);
bL2->Bpred = b->Bpred;
b->Bpred = NULL;
/* Remove bL2 from successors of b */
list_free(&b->Bsucc,FPNULL);
/* fix up successor list of predecessors */
for (bl = bL2->Bpred; bl; bl = list_next(bl))
{ register list_t bs;
for (bs=list_block(bl)->Bsucc; bs; bs=list_next(bs))
if (list_block(bs) == b)
list_ptr(bs) = (void *)bL2;
}
merge++;
cmes3("block %p merged with %p\n",b,bL2);
if (b == startblock)
{ /* bL2 is the new startblock */
block **pb;
cmes("bL2 is new startblock\n");
/* Remove bL2 from list of blocks */
for (pb = &startblock; 1; pb = &(*pb)->Bnext)
{ assert(*pb);
if (*pb == bL2)
{ *pb = bL2->Bnext;
break;
}
}
/* And relink bL2 at the start */
bL2->Bnext = startblock->Bnext;
startblock = bL2; /* new start */
block_free(b);
numblks--;
break; /* dfo[] is now invalid */
}
}
}
}
return merge;
}
/*******************************
* Combine together blocks that are identical.
*/
STATIC void blident()
{ block *bn;
block *bnext;
cmes("blident()\n");
assert(startblock);
#if SCPP
// Determine if any asm blocks
int anyasm = 0;
for (bn = startblock; bn; bn = bn->Bnext)
{ if (bn->BC == BCasm)
{ anyasm = 1;
break;
}
}
#endif
for (bn = startblock; bn; bn = bnext)
{ block *b;
bnext = bn->Bnext;
if (bn->Bflags & BFLnomerg)
continue;
for (b = bnext; b; b = b->Bnext)
{
/* Blocks are identical if: */
/* BC match */
/* not optimized for time or it's a return */
/* (otherwise looprotate() is undone) */
/* successors match */
/* elems match */
if (b->BC == bn->BC &&
//(!OPTIMIZER || !(mfoptim & MFtime) || !b->Bsucc) &&
(!OPTIMIZER || !(b->Bflags & BFLnomerg) || !b->Bsucc) &&
list_equal(b->Bsucc,bn->Bsucc) &&
#if SCPP || NTEXCEPTIONS
b->Btry == bn->Btry &&
#endif
el_match(b->Belem,bn->Belem)
)
{ /* Eliminate block bn */
list_t bl;
switch (b->BC)
{
case BCswitch:
if (memcmp(b->BS.Bswitch,bn->BS.Bswitch,list_nitems(bn->Bsucc) * sizeof(*bn->BS.Bswitch)))
continue;
break;
#if SCPP
case BCtry:
case BCcatch:
#endif
#if MARS
case BCjcatch:
#endif
case BC_try:
case BC_finally:
case BCasm:
Lcontinue:
continue;
}
assert(!b->Bcode);
for (bl = bn->Bpred; bl; bl = list_next(bl))
{ block *bp;
bp = list_block(bl);
if (bp->BC == BCasm)
// Can't do this because of jmp's and loop's
goto Lcontinue;
}
#if 0 && SCPP
// Predecessors must all be at the same btry level.
if (bn->Bpred)
{ block *bp;
bp = list_block(bn->Bpred);
btry = bp->Btry;
if (bp->BC == BCtry)
btry = bp;
}
else
btry = NULL;
for (bl = b->Bpred; bl; bl = list_next(bl))
{ block *bp;
bp = list_block(bl);
if (bp->BC != BCtry)
bp = bp->Btry;
if (btry != bp)
goto Lcontinue;
}
#endif
// if bn is startblock, eliminate b instead of bn
if (bn == startblock)
{
goto Lcontinue; // can't handle predecessors to startblock
bn = b;
b = startblock; /* swap b and bn */
}
#if SCPP
// Don't do it if any predecessors are ASM blocks, since
// we'd have to walk the code list to fix up any jmps.
if (anyasm)
{
for (bl = bn->Bpred; bl; bl = list_next(bl))
{ list_t bls;
block *bp;
bp = list_block(bl);
if (bp->BC == BCasm)
goto Lcontinue;
for (bls=bp->Bsucc; bls; bls=list_next(bls))
if (list_block(bls) == bn &&
list_block(bls)->BC == BCasm)
goto Lcontinue;
}
}
#endif
/* Change successors to predecessors of bn to point to */
/* b instead of bn */
for (bl = bn->Bpred; bl; bl = list_next(bl))
{ list_t bls;
block *bp;
bp = list_block(bl);
for (bls=bp->Bsucc; bls; bls=list_next(bls))
if (list_block(bls) == bn)
{ list_ptr(bls) = (void *)b;
list_prepend(&b->Bpred,bp);
}
}
/* Entirely remove predecessor list from bn. */
/* elimblks() will delete bn entirely. */
list_free(&(bn->Bpred),FPNULL);
#ifdef DEBUG
assert(bn->BC != BCcatch);
if (debugc)
dbg_printf("block B%d (%p) removed, it was same as B%d (%p)\n",
bn->Bdfoidx,bn,b->Bdfoidx,b);
#endif
changes++;
break;
}
}
}
}
/**********************************
* Split out return blocks so the returns can be combined into a
* single block by blident().
*/
STATIC void blreturn()
{
if (!(mfoptim & MFtime)) /* if optimized for space */
{
int retcount; /* number of return counts */
block *b;
retcount = 0;
/* Find last return block */
for (b = startblock; b; b = b->Bnext)
{ if (b->BC == BCret)
retcount++;
if (b->BC == BCasm)
return; // mucks up blident()
}
if (retcount < 2) /* quit if nothing to combine */
return;
/* Split return blocks */
for (b = startblock; b; b = b->Bnext)
{ if (b->BC != BCret)
continue;
#if SCPP || NTEXCEPTIONS
// If no other blocks with the same Btry, don't split
#if SCPP
if (config.flags3 & CFG3eh)
#endif
{
for (block *b2 = startblock; b2; b2 = b2->Bnext)
{
if (b2->BC == BCret && b != b2 && b->Btry == b2->Btry)
goto L1;
}
continue;
}
L1: ;
#endif
if (b->Belem)
{ /* Split b into a goto and a b */
block *bn;
#ifdef DEBUG
if (debugc)
dbg_printf("blreturn: splitting block B%d\n",b->Bdfoidx);
#endif
numblks++;
bn = block_calloc();
bn->BC = BCret;
bn->Bnext = b->Bnext;
#if SCPP || NTEXCEPTIONS
bn->Btry = b->Btry;
#endif
b->BC = BCgoto;
b->Bnext = bn;
list_append(&b->Bsucc,bn);
list_append(&bn->Bpred,b);
b = bn;
}
}
blident(); /* combine return blocks */
}
}
/*****************************************
* Convert expression into a list.
* Construct the list in reverse, that is, so that the right-most
* expression occurs first in the list.
*/
STATIC list_t bl_enlist(elem *e)
{ list_t el = NULL;
if (e)
{
elem_debug(e);
if (e->Eoper == OPcomma)
{ list_t el2;
list_t pl;
el2 = bl_enlist(e->E1);
el = bl_enlist(e->E2);
e->E1 = e->E2 = NULL;
el_free(e);
/* Append el2 list to el */
assert(el);
for (pl = el; list_next(pl); pl = list_next(pl))
;
list_next(pl) = el2;
}
else
list_prepend(&el,e);
}
return el;
}
/*****************************************
* Take a list of expressions and convert it back into an expression tree.
*/
STATIC elem * bl_delist(list_t el)
{ elem *e;
list_t elstart = el;
for (e = NULL; el; el = list_next(el))
e = el_combine(list_elem(el),e);
list_free(&elstart,FPNULL);
return e;
}
/*****************************************
* Do tail merging.
*/
STATIC void bltailmerge()
{
cmes("bltailmerge()\n");
assert(!PARSER && OPTIMIZER);
if (!(mfoptim & MFtime)) /* if optimized for space */
{
block *b;
block *bn;
list_t bl;
elem *e;
elem *en;
/* Split each block into a reversed linked list of elems */
for (b = startblock; b; b = b->Bnext)
b->Blist = bl_enlist(b->Belem);
/* Search for two blocks that have the same successor list.
If the first expressions both lists are the same, split
off a new block with that expression in it.
*/
for (b = startblock; b; b = b->Bnext)
{
if (!b->Blist)
continue;
e = list_elem(b->Blist);
elem_debug(e);
for (bn = b->Bnext; bn; bn = bn->Bnext)
{
if (b->BC == bn->BC &&
list_equal(b->Bsucc,bn->Bsucc) &&
bn->Blist &&
el_match(e,(en = list_elem(bn->Blist)))
#if SCPP || NTEXCEPTIONS
&& b->Btry == bn->Btry
#endif
)
{
switch (b->BC)
{
case BCswitch:
if (memcmp(b->BS.Bswitch,bn->BS.Bswitch,list_nitems(bn->Bsucc) * sizeof(*bn->BS.Bswitch)))
continue;
break;
#if SCPP
case BCtry:
case BCcatch:
#endif
#if MARS
case BCjcatch:
#endif
case BC_try:
case BC_finally:
case BCasm:
continue;
}
/* We've got a match */
block *bnew;
/* Create a new block, bnew, which will be the
merged block. Physically locate it just after bn.
*/
#ifdef DEBUG
if (debugc)
dbg_printf("tail merging: %p and %p\n", b, bn);
#endif
numblks++;
bnew = block_calloc();
bnew->Bnext = bn->Bnext;
bnew->BC = b->BC;
#if SCPP || NTEXCEPTIONS
bnew->Btry = b->Btry;
#endif
if (bnew->BC == BCswitch)
{
bnew->BS.Bswitch = b->BS.Bswitch;
b->BS.Bswitch = NULL;
bn->BS.Bswitch = NULL;
}
bn->Bnext = bnew;
/* The successor list to bnew is the same as b's was */
bnew->Bsucc = b->Bsucc;
b->Bsucc = NULL;
list_free(&bn->Bsucc,FPNULL);
/* Update the predecessor list of the successor list
of bnew, from b to bnew, and removing bn
*/
for (bl = bnew->Bsucc; bl; bl = list_next(bl))
{
list_subtract(&list_block(bl)->Bpred,b);
list_subtract(&list_block(bl)->Bpred,bn);
list_append(&list_block(bl)->Bpred,bnew);
}
/* The predecessors to bnew are b and bn */
list_append(&bnew->Bpred,b);
list_append(&bnew->Bpred,bn);
/* The successors to b and bn are bnew */
b->BC = BCgoto;
bn->BC = BCgoto;
list_append(&b->Bsucc,bnew);
list_append(&bn->Bsucc,bnew);
changes++;
/* Find all the expressions we can merge */
do
{
list_append(&bnew->Blist,e);
el_free(en);
list_pop(&b->Blist);
list_pop(&bn->Blist);
if (!b->Blist)
goto nextb;
e = list_elem(b->Blist);
if (!bn->Blist)
break;
en = list_elem(bn->Blist);
} while (el_match(e,en));
}
}
nextb: ;
}
/* Recombine elem lists into expression trees */
for (b = startblock; b; b = b->Bnext)
b->Belem = bl_delist(b->Blist);
}
}
/**********************************
* Rearrange blocks to minimize jmp's.
*/
STATIC void brmin()
{ block *b;
block *bnext;
list_t bl,blp;
#if SCPP
// Dunno how this may mess up generating EH tables.
if (config.flags3 & CFG3eh) // if EH turned on
return;
#endif
cmes("brmin()\n");
debug_assert(startblock);
for (b = startblock->Bnext; b; b = b->Bnext)
{
bnext = b->Bnext;
if (!bnext)
break;
for (bl = b->Bsucc; bl; bl = list_next(bl))
{ block *bs;
bs = list_block(bl);
if (bs == bnext)
goto L1;
}
// b is a block which does not have bnext as a successor.
// Look for a successor of b for which everyone must jmp to.
for (bl = b->Bsucc; bl; bl = list_next(bl))
{ block *bs;
block *bn;
bs = list_block(bl);
for (blp = bs->Bpred; blp; blp = list_next(blp))
{ block *bsp;
bsp = list_block(blp);
if (bsp->Bnext == bs)
goto L2;
}
// Move bs so it is the Bnext of b
for (bn = bnext; 1; bn = bn->Bnext)
{
if (!bn)
goto L2;
if (bn->Bnext == bs)
break;
}
#if 1
bn->Bnext = NULL;
b->Bnext = bs;
for (bn = bs; bn->Bnext; bn = bn->Bnext)
;
bn->Bnext = bnext;
#else
bn->Bnext = bs->Bnext;
bs->Bnext = bnext;
b->Bnext = bs;
#endif
cmes3("Moving block %p to appear after %p\n",bs,b);
changes++;
break;
L2: ;
}
L1: ;
}
}
/********************************
* Check integrity of blocks.
*/
#if 0
STATIC void block_check()
{ block *b;
list_t bl;
for (b = startblock; b; b = b->Bnext)
{ int nsucc;
int npred;
nsucc = list_nitems(b->Bsucc);
npred = list_nitems(b->Bpred);
switch (b->BC)
{
case BCgoto:
assert(nsucc == 1);
break;
case BCiftrue:
assert(nsucc == 2);
break;
}
for (bl = b->Bsucc; bl; bl = list_next(bl))
{ block *bs = list_block(bl);
list_t bls;
for (bls = bs->Bpred; 1; bls = list_next(bls))
{
assert(bls);
if (list_block(bls) == b)
break;
}
}
}
}
#endif
/***************************************
* Do tail recursion.
*/
STATIC void brtailrecursion()
{ block *b;
block *bs;
elem **pe;
#if SCPP
// if (tyvariadic(funcsym_p->Stype))
return;
return; // haven't dealt with struct params, and ctors/dtors
#endif
if (funcsym_p->Sfunc->Fflags3 & Fnotailrecursion)
return;
if (localgot)
{ /* On OSX, tail recursion will result in two OPgot's:
int status5;
struct MyStruct5 { }
void rec5(int i, MyStruct5 s)
{
if( i > 0 )
{ status5++;
rec5(i-1, s);
}
}
*/
return;
}
for (b = startblock; b; b = b->Bnext)
{
if (b->BC == BC_try)
return;
pe = &b->Belem;
block *bn = NULL;
if (*pe &&
(b->BC == BCret ||
b->BC == BCretexp ||
(b->BC == BCgoto && (bn = list_block(b->Bsucc))->Belem == NULL &&
bn->BC == BCret)
)
)
{ elem *e;
if (el_anyframeptr(*pe))
return;
while ((*pe)->Eoper == OPcomma)
pe = &(*pe)->E2;
e = *pe;
if (OTcall(e->Eoper) &&
e->E1->Eoper == OPvar &&
e->E1->EV.sp.Vsym == funcsym_p)
{
//printf("before:\n");
//elem_print(*pe);
if (OTunary(e->Eoper))
{ *pe = el_long(TYint,0);
}
else
{ int si = 0;
elem *e2 = NULL;
*pe = assignparams(&e->E2,&si,&e2);
*pe = el_combine(*pe,e2);
}
el_free(e);
//printf("after:\n");
//elem_print(*pe);
if (b->BC == BCgoto)
{ list_subtract(&b->Bsucc,bn);
list_subtract(&bn->Bpred,b);
}
b->BC = BCgoto;
list_append(&b->Bsucc,startblock);
list_append(&startblock->Bpred,b);
// Create a new startblock, bs, because startblock cannot
// have predecessors.
numblks++;
bs = block_calloc();
bs->BC = BCgoto;
bs->Bnext = startblock;
list_append(&bs->Bsucc,startblock);
list_append(&startblock->Bpred,bs);
startblock = bs;
cmes("tail recursion\n");
changes++;
return;
}
}
}
}
/*****************************************
* Convert parameter expression to assignment statements.
*/
STATIC elem * assignparams(elem **pe,int *psi,elem **pe2)
{
elem *e = *pe;
if (e->Eoper == OPparam)
{ elem *ea = NULL;
elem *eb = NULL;
elem *e2 = assignparams(&e->E2,psi,&eb);
elem *e1 = assignparams(&e->E1,psi,&ea);
e->E1 = NULL;
e->E2 = NULL;
e = el_combine(e1,e2);
*pe2 = el_combine(eb,ea);
}
else
{ int si = *psi;
Symbol *sp;
Symbol *s;
int op;
elem *es;
type *t;
assert(si < globsym.top);
sp = globsym.tab[si];
s = symbol_genauto(sp->Stype);
s->Sfl = FLauto;
op = OPeq;
if (e->Eoper == OPstrpar)
{
op = OPstreq;
t = e->ET;
elem *ex = e;
e = e->E1;
ex->E1 = NULL;
el_free(ex);
}
es = el_var(s);
es->Ety = e->Ety;
e = el_bin(op,TYvoid,es,e);
if (op == OPstreq)
e->ET = t;
*pe2 = el_bin(op,TYvoid,el_var(sp),el_copytree(es));
(*pe2)->E1->Ety = es->Ety;
if (op == OPstreq)
(*pe2)->ET = t;
*psi = ++si;
*pe = NULL;
}
return e;
}
/****************************************************
* Eliminate empty loops.
*/
STATIC void emptyloops()
{
block *b;
cmes("emptyloops()\n");
for (b = startblock; b; b = b->Bnext)
{
if (b->BC == BCiftrue &&
list_block(b->Bsucc) == b &&
list_nitems(b->Bpred) == 2)
{ block *bpred;
elem *einit;
elem *erel;
elem *einc;
// Find predecessor to b
bpred = list_block(b->Bpred);
if (bpred == b)
bpred = list_block(list_next(b->Bpred));
if (!bpred->Belem)
continue;
// Find einit
for (einit = bpred->Belem; einit->Eoper == OPcomma; einit = einit->E2)
;
if (einit->Eoper != OPeq ||
einit->E2->Eoper != OPconst ||
einit->E1->Eoper != OPvar)
continue;
#if 1
// Look for ((i += 1) < limit)
erel = b->Belem;
if (erel->Eoper != OPlt ||
erel->E2->Eoper != OPconst ||
erel->E1->Eoper != OPaddass)
continue;
einc = erel->E1;
if (einc->E2->Eoper != OPconst ||
einc->E1->Eoper != OPvar ||
!el_match(einc->E1,einit->E1))
continue;
if (!tyintegral(einit->E1->Ety) ||
el_tolong(einc->E2) != 1 ||
el_tolong(einit->E2) >= el_tolong(erel->E2)
)
continue;
{
erel->Eoper = OPeq;
erel->Ety = erel->E1->Ety;
erel->E1 = el_selecte1(erel->E1);
b->BC = BCgoto;
list_subtract(&b->Bsucc,b);
list_subtract(&b->Bpred,b);
#ifdef DEBUG
if (debugc)
{ WReqn(erel);
dbg_printf(" eliminated loop\n");
}
#endif
changes++;
}
#else
// Find einc and erel
if (b->Belem->Eoper != OPcomma)
continue;
einc = b->Belem->E1;
erel = b->Belem->E2;
if (einc->Eoper != OPaddass ||
einc->E1->Eoper != OPvar ||
einc->E2->Eoper != OPconst ||
erel->Eoper != OPlt ||
erel->E1->Eoper != OPvar ||
erel->E2->Eoper != OPconst ||
!el_match(einit->E1,einc->E1) ||
!el_match(einit->E1,erel->E1)
)
continue;
if (!tyintegral(einit->E1->Ety) ||
el_tolong(einc->E2) != 1 ||
el_tolong(einit->E2) >= el_tolong(erel->E2)
)
continue;
{
erel->Eoper = OPeq;
erel->Ety = erel->E1->Ety;
b->BC = BCgoto;
list_subtract(&b->Bsucc,b);
list_subtract(&b->Bpred,b);
#ifdef DEBUG
if (debugc)
{ WReqn(erel);
dbg_printf(" eliminated loop\n");
}
#endif
changes++;
}
#endif
}
}
}
/******************************************
* Determine if function has any side effects.
* This means, determine if all the function does is return a value;
* no extraneous definitions or effects or exceptions.
* A function with no side effects can be CSE'd. It does not reference
* statics or indirect references.
*/
STATIC int funcsideeffect_walk(elem *e);
void funcsideeffects()
{
#if MARS
block *b;
//printf("funcsideeffects('%s')\n",funcsym_p->Sident);
for (b = startblock; b; b = b->Bnext)
{
if (b->Belem && funcsideeffect_walk(b->Belem))
goto Lside;
}
Lnoside:
funcsym_p->Sfunc->Fflags3 |= Fnosideeff;
//printf(" function '%s' has no side effects\n",funcsym_p->Sident);
//return;
Lside:
//printf(" function '%s' has side effects\n",funcsym_p->Sident);
;
#endif
}
#if MARS
STATIC int funcsideeffect_walk(elem *e)
{ int op;
Symbol *s;
assert(e);
elem_debug(e);
if (typemask(e) & mTYvolatile)
goto Lside;
op = e->Eoper;
switch (op)
{
case OPcall:
case OPucall:
if (e->E1->Eoper == OPvar &&
tyfunc((s = e->E1->EV.sp.Vsym)->Stype->Tty) &&
((s->Sfunc && s->Sfunc->Fflags3 & Fnosideeff) || s == funcsym_p)
)
break;
goto Lside;
case OParray:
case OPfield:
goto Lside; // these can throw exceptions
// Note: we should allow assignments to local variables as
// not being a 'side effect'.
default:
assert(op < OPMAX);
return OTsideff(op) ||
(OTunary(op) && funcsideeffect_walk(e->E1)) ||
(OTbinary(op) && (funcsideeffect_walk(e->E1) ||
funcsideeffect_walk(e->E2)));
}
return 0;
Lside:
return 1;
}
#endif
/*******************************
* Determine if there are any OPframeptr's in the tree.
*/
int el_anyframeptr(elem *e)
{
while (1)
{
if (OTunary(e->Eoper))
e = e->E1;
else if (OTbinary(e->Eoper))
{ if (el_anyframeptr(e->E2))
return 1;
e = e->E1;
}
else if (e->Eoper == OPframeptr)
return 1;
else
break;
}
return 0;
}
#endif //!SPP