mirror of https://git.wuffs.org/MWCC
1832 lines
51 KiB
C
1832 lines
51 KiB
C
#include "compiler/COptimizer.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/CClass.h"
|
|
#include "compiler/CDecl.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CExpr.h"
|
|
#include "compiler/CFunc.h"
|
|
#include "compiler/CInt64.h"
|
|
#include "compiler/CMachine.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/InlineAsm.h"
|
|
#include "compiler/enode.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler/CodeGen.h"
|
|
#include "compiler/Switch.h"
|
|
#include "compiler/Exceptions.h"
|
|
#include "compiler/IrOptimizer.h"
|
|
#include "cos.h"
|
|
|
|
COptBlock *basicblocks;
|
|
Boolean copt_isleaffunction;
|
|
static Boolean stmtchanged;
|
|
static COptBlock *currentblock;
|
|
static ENode *mexpr;
|
|
static short setbytes;
|
|
static COptCSE *csenodes[MAXEXPR];
|
|
static COptCSEList *cselist;
|
|
static short extravars;
|
|
static Boolean cse_found;
|
|
static Boolean cse_invals;
|
|
static Boolean static_for_inlines;
|
|
static short replaces;
|
|
static ENode *objrefnode;
|
|
static int objrefnodes;
|
|
|
|
static short bitmasks[] = {
|
|
1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
|
|
0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000
|
|
};
|
|
|
|
// forward decls
|
|
static COptCSE *cse_expression(ENode *expr);
|
|
|
|
static COptCSE *cse_new(ENode *expr) {
|
|
COptCSE *cse = oalloc(sizeof(COptCSE));
|
|
cse->expr = expr;
|
|
cse->replaced = NULL;
|
|
cse->block = currentblock;
|
|
cse->mexpr = mexpr;
|
|
cse->left = NULL;
|
|
cse->right = NULL;
|
|
cse->x1C = 1;
|
|
return cse;
|
|
}
|
|
|
|
static COptCSE *cse_append(COptCSE *cse, ENode *expr) {
|
|
COptCSEList *list = oalloc(sizeof(COptCSEList));
|
|
list->next = cselist;
|
|
cselist = list;
|
|
list->cse = cse;
|
|
list->expr = expr;
|
|
return cse;
|
|
}
|
|
|
|
static void cse_cleanup(void) {
|
|
COptCSEList *scanlist;
|
|
COptCSEList *prevlist;
|
|
COptCSE *scan;
|
|
COptCSE *prev;
|
|
short op;
|
|
|
|
scanlist = cselist;
|
|
while (scanlist && !scanlist->cse)
|
|
scanlist = scanlist->next;
|
|
cselist = scanlist;
|
|
|
|
if (scanlist) {
|
|
do {
|
|
prevlist = scanlist;
|
|
do {
|
|
scanlist = scanlist->next;
|
|
} while (scanlist && !scanlist->cse);
|
|
prevlist->next = scanlist;
|
|
} while (scanlist);
|
|
}
|
|
|
|
for (op = 0; op < MAXEXPR; op++) {
|
|
scan = csenodes[op];
|
|
while (scan && scan->x1C < 0)
|
|
scan = scan->next;
|
|
csenodes[op] = scan;
|
|
|
|
if (scan) {
|
|
do {
|
|
prev = scan;
|
|
do {
|
|
scan = scan->next;
|
|
} while (scan && scan->x1C < 0);
|
|
prev->next = scan;
|
|
} while (scan);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void cse_inval(COptCSE *cse) {
|
|
COptCSEList *scanlist;
|
|
COptCSE *scan;
|
|
short op;
|
|
|
|
if (cse) {
|
|
for (scanlist = cselist; scanlist; scanlist = scanlist->next) {
|
|
if (scanlist->cse == cse) {
|
|
scanlist->cse = NULL;
|
|
scanlist->expr = NULL;
|
|
}
|
|
}
|
|
|
|
cse->x1C = -1;
|
|
cse->left = NULL;
|
|
cse->right = NULL;
|
|
|
|
for (op = 0; op < MAXEXPR; op++) {
|
|
for (scan = csenodes[op]; scan; scan = scan->next) {
|
|
if (scan->left == cse || scan->right == cse)
|
|
cse_inval(scan);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void cse_update_usages(COptCSE *cse, short amount) {
|
|
cse->x1C /= amount;
|
|
if (cse->left)
|
|
cse_update_usages(cse->left, amount);
|
|
if (cse->right)
|
|
cse_update_usages(cse->right, amount);
|
|
}
|
|
|
|
static void cse_replace(ENode *expr, COptCSE *cse) {
|
|
COptCSEList *list;
|
|
|
|
for (list = cselist; list; list = list->next) {
|
|
if (list->cse == cse) {
|
|
*list->expr = *expr;
|
|
replaces++;
|
|
list->cse = NULL;
|
|
list->expr = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
static short cse_objectcost(Object *obj) {
|
|
if (obj->datatype == DLOCAL && !obj->u.var.info->noregister)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
static void cse_treereplacemexpr(COptCSE *cse, ENode *from, ENode *to) {
|
|
if (cse->mexpr == from)
|
|
cse->mexpr = to;
|
|
if (cse->left)
|
|
cse_treereplacemexpr(cse->left, from, to);
|
|
if (cse->right)
|
|
cse_treereplacemexpr(cse->right, from, to);
|
|
}
|
|
|
|
static Boolean cse_issubcse(COptCSE *a, COptCSE *b) {
|
|
if (a == b)
|
|
return 1;
|
|
if (b->left && cse_issubcse(a, b->left))
|
|
return 1;
|
|
if (b->right && cse_issubcse(a, b->right))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static short cse_cost(COptCSE *cse) {
|
|
short cost;
|
|
|
|
if (cse) {
|
|
while (ENODE_IS(cse->expr, ETYPCON) && cse->expr->rtype->type == cse->expr->data.monadic->rtype->type && cse->expr->rtype->size == cse->expr->data.monadic->rtype->size)
|
|
cse = cse->left;
|
|
|
|
if (ENODE_IS_INDIRECT_TO(cse->expr, EOBJREF))
|
|
return cse_objectcost(cse->expr->data.monadic->data.objref);
|
|
|
|
cost = 1;
|
|
if (!copts.optimize_for_size) {
|
|
if (ENODE_IS3(cse->expr, EMUL, EDIV, EMODULO))
|
|
cost = 2;
|
|
}
|
|
return cse_cost(cse->left) + cse_cost(cse->right) + cost;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void cse_remove(void) {
|
|
short op; // r27
|
|
COptCSE *cse; // r25
|
|
COptCSE *best_cse; // r28
|
|
int best_cost; // r30
|
|
Object *obj; // r31
|
|
Boolean did_replacement; // r24
|
|
VarInfo *vi; // r27
|
|
ObjectList *objlist;
|
|
ENode *expr1;
|
|
ENode *expr2;
|
|
ENode *expr3;
|
|
ENode *expr4;
|
|
ENode *mexprsave;
|
|
COptCSEList *list;
|
|
short cost;
|
|
|
|
while (1) {
|
|
op = 0;
|
|
best_cse = NULL;
|
|
best_cost = 0;
|
|
did_replacement = 0;
|
|
|
|
for (; op < MAXEXPR; op++) {
|
|
switch (op) {
|
|
case EINTCONST:
|
|
case EFLOATCONST:
|
|
case EOBJREF:
|
|
case EVECTOR128CONST:
|
|
break;
|
|
default:
|
|
for (cse = csenodes[op]; cse; cse = cse->next) {
|
|
if (cse->x1C > 1 && (cost = cse_cost(cse)) > 4) {
|
|
if (cse->replaced) {
|
|
replaces = 0;
|
|
cse_replace(cse->replaced, cse);
|
|
CError_ASSERT(348, replaces >= 1);
|
|
cse_found = 1;
|
|
did_replacement = 1;
|
|
cse_update_usages(cse, cse->x1C);
|
|
} else {
|
|
if ((cse->x1C * cost) > best_cost) {
|
|
best_cse = cse;
|
|
best_cost = cse->x1C * cost;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (did_replacement)
|
|
continue;
|
|
if (!best_cse || extravars >= 256)
|
|
return;
|
|
|
|
obj = lalloc(sizeof(Object));
|
|
memclrw(obj, sizeof(Object));
|
|
obj->name = CParser_GetUniqueName();
|
|
obj->type = cse->expr->rtype;
|
|
obj->datatype = DLOCAL;
|
|
vi = CodeGen_GetNewVarInfo();
|
|
obj->u.var.info = vi;
|
|
|
|
objlist = lalloc(sizeof(ObjectList));
|
|
objlist->object = obj;
|
|
objlist->next = locals;
|
|
locals = objlist;
|
|
|
|
vi->used = 1;
|
|
vi->usage = cse->x1C + 1;
|
|
|
|
expr1 = lalloc(sizeof(ENode));
|
|
expr1->type = EOBJREF;
|
|
expr1->cost = 0;
|
|
expr1->flags = 0;
|
|
expr1->data.objref = obj;
|
|
expr1->rtype = CDecl_NewPointerType(obj->type);
|
|
|
|
expr2 = lalloc(sizeof(ENode));
|
|
expr2->type = EINDIRECT;
|
|
expr2->cost = 1;
|
|
expr2->flags = 0;
|
|
expr2->data.monadic = expr1;
|
|
expr2->rtype = obj->type;
|
|
|
|
expr3 = lalloc(sizeof(ENode));
|
|
expr3->type = EASS;
|
|
expr3->cost = -1;
|
|
expr3->flags = 0;
|
|
expr3->rtype = obj->type;
|
|
expr3->data.diadic.left = expr2;
|
|
expr3->data.diadic.right = lalloc(sizeof(ENode));
|
|
|
|
*expr3->data.diadic.right = *cse->expr;
|
|
cse->expr = expr3->data.diadic.right;
|
|
|
|
replaces = 0;
|
|
cse_replace(expr2, cse);
|
|
cse->replaced = expr2;
|
|
|
|
if (replaces < 2)
|
|
CError_FATAL(390);
|
|
else
|
|
cse_found = 1;
|
|
|
|
expr4 = lalloc(sizeof(ENode));
|
|
*expr4 = *cse->mexpr;
|
|
|
|
cse->mexpr->type = ECOMMA;
|
|
cse->mexpr->data.diadic.left = expr3;
|
|
cse->mexpr->data.diadic.right = expr4;
|
|
|
|
cse_update_usages(cse, cse->x1C);
|
|
extravars++;
|
|
|
|
mexprsave = cse->mexpr;
|
|
if (mexpr == mexprsave)
|
|
mexpr = expr4;
|
|
|
|
for (list = cselist; list; list = list->next) {
|
|
if (list->cse && !cse_issubcse(list->cse, cse)) {
|
|
if (list->cse->mexpr == mexprsave)
|
|
list->cse->mexpr = expr4;
|
|
if (list->cse->expr == mexprsave)
|
|
list->cse->expr = expr4;
|
|
if (list->expr == mexprsave)
|
|
list->expr = expr4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static COptCSE *cse_intconst(ENode *expr) {
|
|
COptCSE *cse = csenodes[EINTCONST];
|
|
|
|
for (; cse; cse = cse->next) {
|
|
if (expr->rtype == cse->expr->rtype)
|
|
if (CInt64_Equal(cse->expr->data.intval, expr->data.intval))
|
|
return cse;
|
|
}
|
|
|
|
cse = cse_new(expr);
|
|
cse->next = csenodes[EINTCONST];
|
|
csenodes[EINTCONST] = cse;
|
|
return cse;
|
|
}
|
|
|
|
static COptCSE *cse_floatconst(ENode *expr) {
|
|
COptCSE *cse = csenodes[EFLOATCONST];
|
|
Float val = expr->data.floatval;
|
|
|
|
for (; cse; cse = cse->next) {
|
|
if (CMach_CalcFloatDiadicBool(cse->expr->rtype, cse->expr->data.floatval, TK_LOGICAL_EQ, val))
|
|
if (expr->rtype == cse->expr->rtype)
|
|
return cse;
|
|
}
|
|
|
|
cse = cse_new(expr);
|
|
cse->next = csenodes[EFLOATCONST];
|
|
csenodes[EFLOATCONST] = cse;
|
|
return cse;
|
|
}
|
|
|
|
static COptCSE *cse_vectorconst(ENode *expr) {
|
|
COptCSE *cse = csenodes[EVECTOR128CONST];
|
|
MWVector128 val = expr->data.vector128val;
|
|
|
|
for (; cse; cse = cse->next) {
|
|
if (CMach_CalcVectorDiadicBool(cse->expr->rtype, &cse->expr->data.vector128val, TK_LOGICAL_EQ, &val))
|
|
if (expr->rtype == cse->expr->rtype)
|
|
return cse;
|
|
}
|
|
|
|
cse = cse_new(expr);
|
|
cse->next = csenodes[EVECTOR128CONST];
|
|
csenodes[EVECTOR128CONST] = cse;
|
|
return cse;
|
|
}
|
|
|
|
static COptCSE *cse_objref(ENode *expr) {
|
|
COptCSE *cse = csenodes[EOBJREF];
|
|
Object *obj = expr->data.objref;
|
|
|
|
for (; cse; cse = cse->next) {
|
|
if (cse->expr->data.objref == obj)
|
|
return cse;
|
|
}
|
|
|
|
cse = cse_new(expr);
|
|
cse->next = csenodes[EOBJREF];
|
|
csenodes[EOBJREF] = cse;
|
|
return cse;
|
|
}
|
|
|
|
static COptCSE *cse_add_monadic_node(ENode *outer, COptCSE *innercse) {
|
|
COptCSE *cse;
|
|
|
|
if (!innercse)
|
|
return NULL;
|
|
|
|
for (cse = csenodes[outer->type]; cse; cse = cse->next) {
|
|
if (cse->left == innercse && cse->expr->rtype == outer->rtype) {
|
|
CError_ASSERT(524, cse->expr != outer);
|
|
cse->x1C++;
|
|
return cse;
|
|
}
|
|
}
|
|
|
|
cse = cse_new(outer);
|
|
cse->next = csenodes[outer->type];
|
|
csenodes[outer->type] = cse;
|
|
cse->left = innercse;
|
|
return cse;
|
|
}
|
|
|
|
static COptCSE *cse_add_typecon_node(ENode *outer, COptCSE *innercse) {
|
|
COptCSE *cse;
|
|
|
|
if (!innercse)
|
|
return NULL;
|
|
|
|
for (cse = csenodes[outer->type]; cse; cse = cse->next) {
|
|
if (cse->left == innercse && cse->expr->rtype == outer->rtype) {
|
|
CError_ASSERT(552, cse->expr != outer);
|
|
cse->x1C++;
|
|
return cse;
|
|
}
|
|
}
|
|
|
|
cse = cse_new(outer);
|
|
cse->next = csenodes[outer->type];
|
|
csenodes[outer->type] = cse;
|
|
cse->left = innercse;
|
|
return cse;
|
|
}
|
|
|
|
static COptCSE *cse_add_diadic_node(ENode *outer, COptCSE *leftcse, COptCSE *rightcse) {
|
|
COptCSE *cse;
|
|
|
|
if (!leftcse || !rightcse)
|
|
return NULL;
|
|
|
|
for (cse = csenodes[outer->type]; cse; cse = cse->next) {
|
|
if (cse->left == leftcse && cse->right == rightcse) {
|
|
CError_ASSERT(581, cse->expr != outer);
|
|
cse->x1C++;
|
|
return cse;
|
|
}
|
|
}
|
|
|
|
cse = cse_new(outer);
|
|
cse->next = csenodes[outer->type];
|
|
csenodes[outer->type] = cse;
|
|
cse->left = leftcse;
|
|
cse->right = rightcse;
|
|
return cse;
|
|
}
|
|
|
|
static COptCSE *cse_add_commdiadic_node(ENode *outer, COptCSE *leftcse, COptCSE *rightcse) {
|
|
COptCSE *cse;
|
|
|
|
if (!leftcse || !rightcse)
|
|
return NULL;
|
|
|
|
for (cse = csenodes[outer->type]; cse; cse = cse->next) {
|
|
if ((cse->left == leftcse && cse->right == rightcse) || (cse->left == rightcse && cse->right == leftcse)) {
|
|
CError_ASSERT(612, cse->expr != outer);
|
|
cse->x1C++;
|
|
return cse;
|
|
}
|
|
}
|
|
|
|
cse = cse_new(outer);
|
|
cse->next = csenodes[outer->type];
|
|
csenodes[outer->type] = cse;
|
|
cse->left = leftcse;
|
|
cse->right = rightcse;
|
|
return cse;
|
|
}
|
|
|
|
static void sfind_objref(ENode *expr) {
|
|
while (1) {
|
|
switch (expr->type) {
|
|
case ETYPCON:
|
|
expr = expr->data.monadic;
|
|
break;
|
|
case EOBJREF:
|
|
objrefnode = expr;
|
|
objrefnodes++;
|
|
return;
|
|
case EADD:
|
|
case ESUB:
|
|
sfind_objref(expr->data.diadic.left);
|
|
expr = expr->data.diadic.right;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static ENode *find_objref_node(ENode *expr) {
|
|
objrefnode = NULL;
|
|
objrefnodes = 0;
|
|
sfind_objref(expr);
|
|
if (objrefnodes == 1)
|
|
return objrefnode;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static void cse_mem_modify(void) {
|
|
COptCSE *cse;
|
|
|
|
for (cse = csenodes[EINDIRECT]; cse; cse = cse->next) {
|
|
if (ENODE_IS(cse->expr->data.monadic, EOBJREF)) {
|
|
Object *obj = cse->expr->data.monadic->data.objref;
|
|
CError_ASSERT(672, obj->datatype != DALIAS);
|
|
if (obj->datatype == DLOCAL && !obj->u.var.info->noregister)
|
|
continue;
|
|
}
|
|
|
|
cse_inval(cse);
|
|
}
|
|
}
|
|
|
|
static void cse_modify_expression(ENode *expr) {
|
|
if (!expr) {
|
|
short op;
|
|
|
|
cse_remove();
|
|
for (op = 0; op < MAXEXPR; op++)
|
|
csenodes[op] = NULL;
|
|
|
|
cselist = NULL;
|
|
freeoheap();
|
|
} else {
|
|
ENode *objnode;
|
|
Object *obj;
|
|
COptCSE *cse;
|
|
|
|
cse_invals = 1;
|
|
if (ENODE_IS(expr, EINDIRECT) && (objnode = find_objref_node(expr->data.monadic))) {
|
|
do {
|
|
obj = objnode->data.objref;
|
|
cse_remove();
|
|
for (cse = csenodes[EINDIRECT]; cse; cse = cse->next) {
|
|
if ((objnode = find_objref_node(cse->expr->data.monadic)) && obj == objnode->data.objref)
|
|
cse_inval(cse);
|
|
}
|
|
|
|
objnode = find_objref_node(expr->data.monadic);
|
|
if (!objnode) {
|
|
cse_mem_modify();
|
|
break;
|
|
}
|
|
} while (obj != objnode->data.objref);
|
|
} else {
|
|
cse_remove();
|
|
cse_mem_modify();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void cse_pascalcall(ENode *expr) {
|
|
ENodeList *list;
|
|
|
|
for (list = expr->data.funccall.args; list; list = list->next)
|
|
cse_expression(list->node);
|
|
|
|
if (ENODE_IS(expr, EFUNCCALLP))
|
|
cse_expression(expr->data.funccall.funcref);
|
|
|
|
cse_remove();
|
|
cse_mem_modify();
|
|
}
|
|
|
|
static Boolean cse_pusharg(ENodeList *exprs, FuncArg *args) {
|
|
Boolean result;
|
|
|
|
if (!exprs)
|
|
return 1;
|
|
|
|
if (args && args != &elipsis && args != &oldstyle)
|
|
args = args->next;
|
|
if (exprs->next)
|
|
result = cse_pusharg(exprs->next, args);
|
|
|
|
cse_expression(exprs->node);
|
|
return result;
|
|
}
|
|
|
|
static void cse_ccall(ENode *expr) {
|
|
if (cse_pusharg(expr->data.funccall.args, expr->data.funccall.functype->args)) {
|
|
if (ENODE_IS(expr, EFUNCCALL))
|
|
cse_expression(expr->data.funccall.funcref);
|
|
|
|
cse_remove();
|
|
cse_mem_modify();
|
|
} else {
|
|
cse_modify_expression(NULL);
|
|
}
|
|
}
|
|
|
|
static COptCSE *cse_expression(ENode *expr) {
|
|
ENode *save;
|
|
COptCSE *tmp;
|
|
ENodeType nt = expr->type;
|
|
|
|
switch (nt) {
|
|
case EFUNCCALL:
|
|
cse_ccall(expr);
|
|
return NULL;
|
|
case EFUNCCALLP:
|
|
cse_pascalcall(expr);
|
|
return NULL;
|
|
case EPOSTINC:
|
|
case EPOSTDEC:
|
|
case EPREINC:
|
|
case EPREDEC:
|
|
save = mexpr;
|
|
mexpr = expr;
|
|
CError_ASSERT(816, ENODE_IS(expr->data.monadic, EINDIRECT));
|
|
|
|
cse_expression(expr->data.monadic->data.monadic);
|
|
cse_modify_expression(expr->data.monadic);
|
|
mexpr = save;
|
|
return NULL;
|
|
|
|
case EINDIRECT:
|
|
case EMONMIN:
|
|
case EBINNOT:
|
|
case ELOGNOT:
|
|
case EFORCELOAD:
|
|
return cse_append(cse_add_monadic_node(expr, cse_expression(expr->data.monadic)), expr);
|
|
|
|
case ETYPCON:
|
|
return cse_append(cse_add_typecon_node(expr, cse_expression(expr->data.monadic)), expr);
|
|
|
|
case EMUL:
|
|
case EMULV:
|
|
case EADDV:
|
|
case EADD:
|
|
case EEQU:
|
|
case ENOTEQU:
|
|
case EAND:
|
|
case EXOR:
|
|
case EOR:
|
|
tmp = cse_expression(expr->data.diadic.left);
|
|
if (expr->type == nt)
|
|
return cse_append(cse_add_commdiadic_node(expr, tmp, cse_expression(expr->data.diadic.right)), expr);
|
|
else
|
|
return NULL;
|
|
|
|
case EDIV:
|
|
case EMODULO:
|
|
case ESUBV:
|
|
case ESUB:
|
|
case ESHL:
|
|
case ESHR:
|
|
case ELESS:
|
|
case EGREATER:
|
|
case ELESSEQU:
|
|
case EGREATEREQU:
|
|
case EPMODULO:
|
|
case EROTL:
|
|
case EROTR:
|
|
case EBTST:
|
|
tmp = cse_expression(expr->data.diadic.left);
|
|
if (expr->type == nt)
|
|
return cse_append(cse_add_diadic_node(expr, tmp, cse_expression(expr->data.diadic.right)), expr);
|
|
else
|
|
return NULL;
|
|
|
|
case EASS:
|
|
case EMULASS:
|
|
case EDIVASS:
|
|
case EMODASS:
|
|
case EADDASS:
|
|
case ESUBASS:
|
|
case ESHLASS:
|
|
case ESHRASS:
|
|
case EANDASS:
|
|
case EXORASS:
|
|
case EORASS:
|
|
CError_ASSERT(887, ENODE_IS(expr->data.diadic.left, EINDIRECT));
|
|
save = mexpr;
|
|
mexpr = expr;
|
|
cse_expression(expr->data.diadic.right);
|
|
if (expr->type == nt) {
|
|
cse_expression(expr->data.diadic.left->data.monadic);
|
|
cse_modify_expression(expr->data.diadic.left);
|
|
mexpr = save;
|
|
return NULL;
|
|
} else {
|
|
cse_modify_expression(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
case ECOMMA:
|
|
cse_expression(expr->data.diadic.left);
|
|
save = mexpr;
|
|
mexpr = expr->data.diadic.right;
|
|
tmp = cse_expression(expr->data.diadic.right);
|
|
mexpr = save;
|
|
return tmp;
|
|
|
|
case EINTCONST:
|
|
return cse_intconst(expr);
|
|
case EFLOATCONST:
|
|
return cse_floatconst(expr);
|
|
case EVECTOR128CONST:
|
|
return cse_vectorconst(expr);
|
|
case EOBJREF:
|
|
return cse_objref(expr);
|
|
|
|
case EBITFIELD:
|
|
cse_modify_expression(NULL);
|
|
return NULL;
|
|
|
|
case ECOND:
|
|
cse_expression(expr->data.cond.cond);
|
|
cse_modify_expression(NULL);
|
|
return NULL;
|
|
|
|
case ENULLCHECK:
|
|
cse_expression(expr->data.nullcheck.nullcheckexpr);
|
|
cse_modify_expression(NULL);
|
|
return NULL;
|
|
|
|
case ELAND:
|
|
case ELOR:
|
|
cse_expression(expr->data.diadic.left);
|
|
cse_modify_expression(NULL);
|
|
return NULL;
|
|
|
|
case ESTRINGCONST:
|
|
case ELABEL:
|
|
return NULL;
|
|
|
|
case EPRECOMP:
|
|
CError_FATAL(948);
|
|
|
|
default:
|
|
CError_FATAL(951);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static void cse_block(COptBlock *block) {
|
|
Statement *stmt;
|
|
COptBlock *check;
|
|
COptBlockList *scan;
|
|
COptBlock *best;
|
|
short i;
|
|
SInt32 counter;
|
|
UInt32 starttime;
|
|
|
|
starttime = COS_GetTicks();
|
|
counter = 0;
|
|
|
|
while (1) {
|
|
cse_invals = 0;
|
|
currentblock = block;
|
|
block->x1E = 1;
|
|
|
|
for (stmt = block->stmt, i = block->x1C; i > 0; stmt = stmt->next, i--) {
|
|
switch (stmt->type) {
|
|
case ST_EXPRESSION:
|
|
case ST_SWITCH:
|
|
case ST_IFGOTO:
|
|
case ST_IFNGOTO:
|
|
mexpr = stmt->expr;
|
|
cse_expression(mexpr);
|
|
break;
|
|
case ST_RETURN:
|
|
mexpr = stmt->expr;
|
|
if (mexpr)
|
|
cse_expression(mexpr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
for (scan = block->blocks2; scan; scan = scan->next) {
|
|
check = scan->block;
|
|
if (!check->x1E && check->blocks && !check->blocks->next && check->blocks->block == block) {
|
|
best = check;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (i != 1)
|
|
break;
|
|
|
|
block = best;
|
|
if (COS_GetTicks() > (starttime + 60)) {
|
|
if (counter++ & 1) {
|
|
if (CWDisplayLines(cparamblkptr->context, lines))
|
|
CError_UserBreak();
|
|
} else {
|
|
if (CWDisplayLines(cparamblkptr->context, lines + 1))
|
|
CError_UserBreak();
|
|
}
|
|
starttime = COS_GetTicks();
|
|
}
|
|
|
|
if (cse_invals)
|
|
cse_cleanup();
|
|
}
|
|
|
|
cse_remove();
|
|
}
|
|
|
|
static void CSE(void) {
|
|
COptBlock *block;
|
|
|
|
for (block = basicblocks->next; block; block = block->next)
|
|
block->x1E = 0;
|
|
|
|
for (block = basicblocks->next; block; block = block->next) {
|
|
if (!block->x1E) {
|
|
short op;
|
|
|
|
for (op = 0; op < MAXEXPR; op++)
|
|
csenodes[op] = NULL;
|
|
|
|
cselist = NULL;
|
|
cse_found = 0;
|
|
cse_block(block);
|
|
freeoheap();
|
|
}
|
|
}
|
|
}
|
|
|
|
static short TestSetBit(short *set, short bit) {
|
|
return set[bit >> 4] & bitmasks[bit & 15];
|
|
}
|
|
|
|
static void SetSetBit(short *set, short bit) {
|
|
set[bit >> 4] |= bitmasks[bit & 15];
|
|
}
|
|
|
|
UInt32 RegAllocMask(short var) {
|
|
COptBlock *block;
|
|
UInt32 mask = 0;
|
|
|
|
for (block = basicblocks; block; block = block->next) {
|
|
if (TestSetBit(block->set1, var) || TestSetBit(block->set2, var))
|
|
mask |= block->allocmask;
|
|
}
|
|
|
|
return mask;
|
|
}
|
|
|
|
void MarkRegAllocMask(short var, short bit, Boolean flag) {
|
|
COptBlock *block;
|
|
UInt32 mask = 1 << bit;
|
|
|
|
if (flag) {
|
|
for (block = basicblocks; block; block = block->next) {
|
|
if (TestSetBit(block->set1, var) || TestSetBit(block->set2, var))
|
|
block->allocmask |= mask;
|
|
}
|
|
} else {
|
|
for (block = basicblocks; block; block = block->next) {
|
|
block->allocmask |= mask;
|
|
}
|
|
}
|
|
}
|
|
|
|
static COptBlock *newblock(void) {
|
|
COptBlock *block;
|
|
short i;
|
|
short max;
|
|
|
|
block = lalloc(sizeof(COptBlock) + (setbytes * 2));
|
|
block->x1E = 0;
|
|
block->next = NULL;
|
|
block->blocks = NULL;
|
|
block->blocks2 = NULL;
|
|
block->allocmask = 0;
|
|
block->set1 = (short *) (((long) block) + sizeof(COptBlock));
|
|
block->set2 = (short *) (((long) block) + setbytes + sizeof(COptBlock));
|
|
|
|
for (i = 0, max = setbytes / 2; i < max; i++) {
|
|
block->set1[i] = 0;
|
|
block->set2[i] = 0;
|
|
}
|
|
|
|
return block;
|
|
}
|
|
|
|
static void MarkFollow(COptBlock *block) {
|
|
COptBlockList *list;
|
|
|
|
restart:
|
|
block->x1E = 1;
|
|
if ((list = block->blocks2)) {
|
|
while (1) {
|
|
if (!list->block->x1E) {
|
|
if (!list->next) {
|
|
block = list->block;
|
|
goto restart;
|
|
}
|
|
MarkFollow(list->block);
|
|
list = list->next;
|
|
} else {
|
|
list = list->next;
|
|
if (!list)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static Boolean CheckInit(short var) {
|
|
Boolean result;
|
|
COptBlock *block;
|
|
|
|
result = 1;
|
|
for (block = basicblocks; block; block = block->next) {
|
|
if (!block->x1E && TestSetBit(block->set2, var))
|
|
MarkFollow(block);
|
|
}
|
|
|
|
for (block = basicblocks; block; block = block->next) {
|
|
if (!block->x1E) {
|
|
if (TestSetBit(block->set1, var))
|
|
result = 0;
|
|
} else {
|
|
block->x1E = 0;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void CheckVarInit(void) {
|
|
COptBlock *block;
|
|
VarInfo *vi;
|
|
ObjectList *list;
|
|
|
|
for (block = basicblocks; block; block = block->next)
|
|
block->x1E = 0;
|
|
|
|
for (list = locals; list; list = list->next) {
|
|
if (list->object->datatype == DLOCAL && !IsTempName(list->object->name) && !is_volatile_object(list->object)) {
|
|
vi = list->object->u.var.info;
|
|
if (vi->used && !CheckInit(vi->varnumber)) {
|
|
if (!IS_TYPE_CLASS(list->object->type) || !CClass_IsEmpty(TYPE_CLASS(list->object->type))) {
|
|
CError_SetErrorToken(&vi->deftoken);
|
|
CError_Warning(CErrorStr185, list->object->name->name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void AddVar(Object *obj, Boolean whichSet) {
|
|
VarInfo *vi;
|
|
|
|
if (obj->datatype == DLOCAL) {
|
|
vi = obj->u.var.info;
|
|
if (!whichSet) {
|
|
SetSetBit(currentblock->set1, vi->varnumber);
|
|
} else {
|
|
if (!TestSetBit(currentblock->set1, vi->varnumber))
|
|
SetSetBit(currentblock->set2, vi->varnumber);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void CheckExpr(ENode *expr) {
|
|
ENodeList *list;
|
|
|
|
while (1) {
|
|
switch (expr->type) {
|
|
case EINDIRECT:
|
|
if (ENODE_IS(expr->data.monadic, EOBJREF)) {
|
|
AddVar(expr->data.monadic->data.objref, 0);
|
|
return;
|
|
}
|
|
expr = expr->data.monadic;
|
|
break;
|
|
case EOBJREF:
|
|
AddVar(expr->data.objref, 1);
|
|
return;
|
|
case EFUNCCALL:
|
|
case EFUNCCALLP:
|
|
CheckExpr(expr->data.funccall.funcref);
|
|
for (list = expr->data.funccall.args; list; list = list->next)
|
|
CheckExpr(list->node);
|
|
return;
|
|
case ECOND:
|
|
CheckExpr(expr->data.cond.cond);
|
|
CheckExpr(expr->data.cond.expr1);
|
|
CheckExpr(expr->data.cond.expr2);
|
|
return;
|
|
case EASS:
|
|
if (ENODE_IS_INDIRECT_TO(expr->data.diadic.left, EOBJREF)) {
|
|
CheckExpr(expr->data.diadic.right);
|
|
AddVar(expr->data.diadic.left->data.monadic->data.objref, 1);
|
|
return;
|
|
}
|
|
case EMUL:
|
|
case EMULV:
|
|
case EDIV:
|
|
case EMODULO:
|
|
case EADDV:
|
|
case ESUBV:
|
|
case EADD:
|
|
case ESUB:
|
|
case ESHL:
|
|
case ESHR:
|
|
case ELESS:
|
|
case EGREATER:
|
|
case ELESSEQU:
|
|
case EGREATEREQU:
|
|
case EEQU:
|
|
case ENOTEQU:
|
|
case EAND:
|
|
case EXOR:
|
|
case EOR:
|
|
case ELAND:
|
|
case ELOR:
|
|
case EMULASS:
|
|
case EDIVASS:
|
|
case EMODASS:
|
|
case EADDASS:
|
|
case ESUBASS:
|
|
case ESHLASS:
|
|
case ESHRASS:
|
|
case EANDASS:
|
|
case EXORASS:
|
|
case EORASS:
|
|
case ECOMMA:
|
|
case EPMODULO:
|
|
case EROTL:
|
|
case EROTR:
|
|
case EBCLR:
|
|
case EBTST:
|
|
case EBSET:
|
|
CheckExpr(expr->data.diadic.left);
|
|
expr = expr->data.diadic.right;
|
|
break;
|
|
case EPOSTINC:
|
|
case EPOSTDEC:
|
|
case EPREINC:
|
|
case EPREDEC:
|
|
case EMONMIN:
|
|
case EBINNOT:
|
|
case ELOGNOT:
|
|
case EFORCELOAD:
|
|
case ETYPCON:
|
|
case EBITFIELD:
|
|
expr = expr->data.monadic;
|
|
break;
|
|
case ENULLCHECK:
|
|
CheckExpr(expr->data.nullcheck.nullcheckexpr);
|
|
expr = expr->data.nullcheck.condexpr;
|
|
break;
|
|
case EINTCONST:
|
|
case EFLOATCONST:
|
|
case ESTRINGCONST:
|
|
case EPRECOMP:
|
|
case ELABEL:
|
|
case EVECTOR128CONST:
|
|
return;
|
|
default:
|
|
CError_FATAL(1332);
|
|
}
|
|
}
|
|
}
|
|
|
|
static short CheckPath(COptBlock *block, short var) {
|
|
COptBlockList *list;
|
|
|
|
if (block->x1E)
|
|
return TestSetBit(block->set1, var);
|
|
|
|
block->x1E = 1;
|
|
if (TestSetBit(block->set1, var))
|
|
return -1;
|
|
if (TestSetBit(block->set2, var))
|
|
return 0;
|
|
|
|
for (list = block->blocks2; list; list = list->next) {
|
|
if (CheckPath(list->block, var)) {
|
|
SetSetBit(block->set1, var);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void MarkPre(COptBlock *block, short var) {
|
|
COptBlockList *list;
|
|
|
|
restart:
|
|
block->x1E = 1;
|
|
for (list = block->blocks; list; list = list->next) {
|
|
if (!list->block->x1E) {
|
|
if (!TestSetBit(list->block->set2, var)) {
|
|
SetSetBit(list->block->set1, var);
|
|
if (!list->next) {
|
|
block = list->block;
|
|
goto restart;
|
|
}
|
|
MarkPre(list->block, var);
|
|
} else {
|
|
list->block->x1E = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void CheckVarUsage(void) {
|
|
short local;
|
|
COptBlock *block;
|
|
short counter;
|
|
|
|
for (currentblock = basicblocks; currentblock; currentblock = currentblock->next) {
|
|
Statement *stmt = currentblock->stmt;
|
|
if (currentblock->x1C > 0 && stmt->type == ST_LABEL && (stmt->flags & StmtFlag_1)) {
|
|
short i;
|
|
for (i = 0; i < localcount; i++)
|
|
SetSetBit(currentblock->set2, i);
|
|
}
|
|
|
|
for (counter = currentblock->x1C; counter > 0; counter--) {
|
|
if (stmt->type >= ST_EXPRESSION && stmt->type <= ST_GOTOEXPR && stmt->expr)
|
|
CheckExpr(stmt->expr);
|
|
stmt = stmt->next;
|
|
}
|
|
}
|
|
|
|
for (local = 0; local < localcount; local++) {
|
|
for (block = basicblocks; block; block = block->next) {
|
|
if (!block->x1E && TestSetBit(block->set1, local))
|
|
MarkPre(block, local);
|
|
}
|
|
for (block = basicblocks; block; block = block->next) {
|
|
block->x1E = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SplitCommaExpressions(void) {
|
|
COptBlock *block;
|
|
Statement *stmt;
|
|
ENode *expr;
|
|
Statement *stmtcopy;
|
|
short counter;
|
|
Boolean flag;
|
|
|
|
block = basicblocks->next;
|
|
while (block) {
|
|
stmt = block->stmt;
|
|
counter = block->x1C;
|
|
flag = 1;
|
|
while (counter > 0) {
|
|
if (stmt->type >= ST_EXPRESSION && stmt->type <= ST_GOTOEXPR) {
|
|
if ((expr = stmt->expr) && ENODE_IS(expr, ECOMMA)) {
|
|
stmtcopy = lalloc(sizeof(Statement));
|
|
*stmtcopy = *stmt;
|
|
stmt->next = stmtcopy;
|
|
stmt->type = ST_EXPRESSION;
|
|
stmt->expr = expr->data.diadic.left;
|
|
stmtcopy->expr = expr->data.diadic.right;
|
|
block->x1C++;
|
|
flag = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
stmt = stmt->next;
|
|
counter--;
|
|
}
|
|
|
|
if (flag)
|
|
block = block->next;
|
|
}
|
|
}
|
|
|
|
static void BasicBlockAnalyze(Statement *stmt) {
|
|
COptBlock *block;
|
|
ObjectList *objlist;
|
|
COptBlockList *scan;
|
|
COptBlockList *list;
|
|
CLabel *label;
|
|
COptBlock *iblock;
|
|
COptBlock *oblock;
|
|
SwitchCase *swcase;
|
|
|
|
setbytes = 2 * ((localcount - 1) / 16) + 2;
|
|
if (copts.global_optimizer) {
|
|
setbytes += 32;
|
|
extravars = 0;
|
|
}
|
|
|
|
block = newblock();
|
|
basicblocks = block;
|
|
block->stmt = NULL;
|
|
block->x1C = 0;
|
|
|
|
if (stmt) {
|
|
list = lalloc(sizeof(COptBlockList));
|
|
list->next = NULL;
|
|
block->blocks2 = list;
|
|
list->block = (COptBlock *) stmt;
|
|
}
|
|
|
|
for (objlist = arguments; objlist; objlist = objlist->next) {
|
|
SetSetBit(block->set2, objlist->object->u.var.info->varnumber);
|
|
}
|
|
|
|
while (stmt) {
|
|
int counter;
|
|
|
|
block->next = newblock();
|
|
block = block->next;
|
|
block->stmt = stmt;
|
|
counter = 1;
|
|
|
|
innerLoop:
|
|
switch (stmt->type) {
|
|
case ST_ASM:
|
|
label = InlineAsm_GetReferencedLabel(stmt);
|
|
if (!label)
|
|
goto jumpahead;
|
|
list = lalloc(sizeof(COptBlockList));
|
|
list->next = block->blocks2;
|
|
block->blocks2 = list;
|
|
list->block = (COptBlock *) label->stmt;
|
|
if (stmt->next) {
|
|
list = lalloc(sizeof(COptBlockList));
|
|
list->next = block->blocks2;
|
|
block->blocks2 = list;
|
|
list->block = (COptBlock *) stmt->next;
|
|
}
|
|
stmt = stmt->next;
|
|
block->x1C = counter;
|
|
continue;
|
|
case ST_NOP:
|
|
case ST_GOTO:
|
|
case ST_ENTRY:
|
|
if (stmt->next && stmt->next->type != ST_LABEL) {
|
|
stmt = stmt->next;
|
|
counter++;
|
|
goto innerLoop;
|
|
}
|
|
break;
|
|
case ST_EXPRESSION:
|
|
case ST_BEGINCATCH:
|
|
case ST_ENDCATCH:
|
|
case ST_ENDCATCHDTOR:
|
|
jumpahead:
|
|
if (stmt->next && stmt->next->type == ST_GOTO) {
|
|
stmt = stmt->next;
|
|
counter++;
|
|
goto innerLoop;
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch (stmt->type) {
|
|
case ST_SWITCH:
|
|
label = ((SwitchInfo *) stmt->label)->defaultlabel;
|
|
if (label != cleanreturnlabel) {
|
|
list = lalloc(sizeof(COptBlockList));
|
|
list->next = block->blocks2;
|
|
block->blocks2 = list;
|
|
list->block = (COptBlock *) label->stmt;
|
|
}
|
|
for (swcase = ((SwitchInfo *) stmt->label)->cases; swcase; swcase = swcase->next) {
|
|
label = swcase->label;
|
|
if (label != cleanreturnlabel) {
|
|
list = lalloc(sizeof(COptBlockList));
|
|
list->next = block->blocks2;
|
|
block->blocks2 = list;
|
|
list->block = (COptBlock *) label->stmt;
|
|
}
|
|
}
|
|
break;
|
|
case ST_RETURN:
|
|
case ST_EXIT:
|
|
case ST_GOTOEXPR:
|
|
break;
|
|
case ST_GOTO:
|
|
case ST_IFGOTO:
|
|
case ST_IFNGOTO:
|
|
case ST_OVF:
|
|
label = stmt->label;
|
|
if (label != cleanreturnlabel) {
|
|
list = lalloc(sizeof(COptBlockList));
|
|
list->next = block->blocks2;
|
|
block->blocks2 = list;
|
|
list->block = (COptBlock *) label->stmt;
|
|
}
|
|
if (stmt->type == ST_GOTO)
|
|
break;
|
|
default:
|
|
if (stmt->next) {
|
|
list = lalloc(sizeof(COptBlockList));
|
|
list->next = block->blocks2;
|
|
block->blocks2 = list;
|
|
list->block = (COptBlock *) stmt->next;
|
|
}
|
|
break;
|
|
}
|
|
|
|
stmt = stmt->next;
|
|
block->x1C = counter;
|
|
}
|
|
|
|
for (oblock = basicblocks; oblock; oblock = oblock->next) {
|
|
for (scan = oblock->blocks2; scan; scan = scan->next) {
|
|
stmt = (Statement *) scan->block;
|
|
for (iblock = basicblocks->next; iblock; iblock = iblock->next) {
|
|
if (iblock->stmt == stmt) {
|
|
scan->block = iblock;
|
|
list = lalloc(sizeof(COptBlockList));
|
|
list->next = iblock->blocks;
|
|
iblock->blocks = list;
|
|
list->block = oblock;
|
|
break;
|
|
}
|
|
}
|
|
|
|
CError_ASSERT(1602, iblock);
|
|
}
|
|
}
|
|
|
|
SplitCommaExpressions();
|
|
CheckVarUsage();
|
|
}
|
|
|
|
static CLabel *finallabel(CLabel *label, Statement *stmt) {
|
|
Statement *scan;
|
|
|
|
for (scan = label->stmt; scan; scan = scan->next) {
|
|
if (scan->type > ST_LABEL) {
|
|
if (scan == stmt)
|
|
return label;
|
|
if (scan->type == ST_GOTO) {
|
|
if (scan->label != label)
|
|
stmtchanged = 1;
|
|
return scan->label;
|
|
}
|
|
return label;
|
|
}
|
|
}
|
|
|
|
return label;
|
|
}
|
|
|
|
static void optimizegoto(Statement *stmt) {
|
|
Statement *scan;
|
|
|
|
for (scan = stmt->next; scan; scan = scan->next) {
|
|
if (stmt->label->stmt == scan) {
|
|
stmt->type = ST_NOP;
|
|
stmtchanged = 1;
|
|
return;
|
|
}
|
|
if (scan->type > ST_LABEL)
|
|
break;
|
|
}
|
|
|
|
stmt->label = finallabel(stmt->label, stmt);
|
|
}
|
|
|
|
static void removeif(Statement *stmt, Boolean flag) {
|
|
if (((stmt->type == ST_IFGOTO) && flag) || ((stmt->type == ST_IFNGOTO) && !flag)) {
|
|
Statement *copy = lalloc(sizeof(Statement));
|
|
*copy = *stmt;
|
|
copy->type = ST_GOTO;
|
|
stmt->next = copy;
|
|
}
|
|
stmt->type = ST_EXPRESSION;
|
|
stmtchanged = 1;
|
|
}
|
|
|
|
static void optimizeif(Statement *stmt) {
|
|
Statement *scan;
|
|
Statement *scan2;
|
|
Boolean flag;
|
|
|
|
if (iszero(stmt->expr)) {
|
|
removeif(stmt, 0);
|
|
return;
|
|
}
|
|
if (isnotzero(stmt->expr)) {
|
|
removeif(stmt, 1);
|
|
return;
|
|
}
|
|
|
|
for (scan = stmt->next, flag = 0; scan; scan = scan->next) {
|
|
if (scan->type > ST_LABEL) {
|
|
if (scan->type == ST_GOTO) {
|
|
if (scan->label == stmt->label) {
|
|
stmt->type = ST_EXPRESSION;
|
|
stmtchanged = 1;
|
|
return;
|
|
}
|
|
|
|
if (!flag) {
|
|
for (scan2 = scan->next; scan2; scan2 = scan2->next) {
|
|
if (scan2->type > ST_LABEL)
|
|
break;
|
|
if (stmt->label->stmt == scan2) {
|
|
stmt->label = scan->label;
|
|
scan->type = ST_NOP;
|
|
if (stmt->type == ST_IFGOTO)
|
|
stmt->type = ST_IFNGOTO;
|
|
else
|
|
stmt->type = ST_IFGOTO;
|
|
stmtchanged = 1;
|
|
stmt->label = finallabel(stmt->label, stmt);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
} else if (scan->type == ST_RETURN && !scan->expr && !static_for_inlines && !flag) {
|
|
for (scan2 = scan->next; scan2; scan2 = scan2->next) {
|
|
if (scan2->type > ST_LABEL)
|
|
break;
|
|
if (stmt->label->stmt == scan2) {
|
|
stmt->label = cleanreturnlabel;
|
|
needs_cleanup = 1;
|
|
scan->type = ST_NOP;
|
|
if (stmt->type == ST_IFGOTO)
|
|
stmt->type = ST_IFNGOTO;
|
|
else
|
|
stmt->type = ST_IFGOTO;
|
|
stmtchanged = 1;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (scan->type == ST_LABEL)
|
|
flag = 1;
|
|
|
|
if (stmt->label->stmt == scan) {
|
|
stmt->type = ST_EXPRESSION;
|
|
stmtchanged = 1;
|
|
return;
|
|
}
|
|
}
|
|
|
|
stmt->label = finallabel(stmt->label, stmt);
|
|
}
|
|
|
|
static void optimizeswitch(Statement *stmt) {
|
|
SwitchInfo *info;
|
|
SwitchCase *swcase;
|
|
|
|
info = (SwitchInfo *) stmt->label;
|
|
CError_ASSERT(1746, info && info->cases && info->defaultlabel);
|
|
|
|
info->defaultlabel = finallabel(info->defaultlabel, stmt);
|
|
for (swcase = info->cases; swcase; swcase = swcase->next)
|
|
swcase->label = finallabel(swcase->label, stmt);
|
|
|
|
if (ENODE_IS(stmt->expr, EINTCONST)) {
|
|
for (swcase = info->cases; swcase; swcase = swcase->next) {
|
|
if (CInt64_GreaterEqual(swcase->min, stmt->expr->data.intval) && CInt64_LessEqual(swcase->max, stmt->expr->data.intval))
|
|
break;
|
|
}
|
|
|
|
stmt->type = ST_GOTO;
|
|
stmt->label = swcase ? swcase->label : info->defaultlabel;
|
|
}
|
|
}
|
|
|
|
static void removeunusedlabels(Statement *stmt) {
|
|
Statement *scan;
|
|
CLabel *label;
|
|
SwitchCase *swcase;
|
|
ExceptionAction *action;
|
|
|
|
for (scan = stmt; scan; scan = scan->next)
|
|
scan->marked = 0;
|
|
|
|
for (scan = stmt; scan; scan = scan->next) {
|
|
switch (scan->type) {
|
|
case ST_GOTO:
|
|
case ST_IFGOTO:
|
|
case ST_IFNGOTO:
|
|
case ST_OVF:
|
|
if (scan->label->stmt)
|
|
scan->label->stmt->marked = 1;
|
|
break;
|
|
case ST_SWITCH:
|
|
((SwitchInfo *) scan->label)->defaultlabel->stmt->marked = 1;
|
|
for (swcase = ((SwitchInfo *) scan->label)->cases; swcase; swcase = swcase->next)
|
|
swcase->label->stmt->marked = 1;
|
|
break;
|
|
case ST_ASM:
|
|
if ((label = InlineAsm_GetReferencedLabel(scan)))
|
|
label->stmt->marked = 1;
|
|
if ((label = InlineAsm_GetReferencedLabel2(scan)))
|
|
label->stmt->marked = 1;
|
|
break;
|
|
case ST_BEGINLOOP:
|
|
((LoopInfo *) scan->expr)->stmt->marked = 1;
|
|
break;
|
|
case ST_ENDLOOP:
|
|
if (scan->next->type == ST_GOTO && scan->next->next->type == ST_LABEL)
|
|
scan->next->next->marked = 1;
|
|
break;
|
|
default:
|
|
for (action = scan->dobjstack; action; action = action->prev) {
|
|
if (action->type == EAT_CATCHBLOCK) {
|
|
action->data.catch_block.catch_label->stmt->marked = 1;
|
|
action->data.catch_block.catch_label->stmt->flags |= StmtFlag_1;
|
|
} else if (action->type == EAT_SPECIFICATION) {
|
|
action->data.specification.unexp_label->stmt->marked = 1;
|
|
action->data.specification.unexp_label->stmt->flags |= StmtFlag_1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (scan = stmt; scan; scan = scan->next) {
|
|
if (scan->type == ST_LABEL && !scan->marked && !(scan->flags & StmtFlag_1)) {
|
|
scan->type = ST_NOP;
|
|
stmtchanged = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void optimizebranches(Statement *stmt) {
|
|
removeunusedlabels(stmt);
|
|
while (stmt) {
|
|
switch (stmt->type) {
|
|
case ST_GOTO:
|
|
optimizegoto(stmt);
|
|
break;
|
|
case ST_IFGOTO:
|
|
case ST_IFNGOTO:
|
|
optimizeif(stmt);
|
|
break;
|
|
case ST_SWITCH:
|
|
optimizeswitch(stmt);
|
|
break;
|
|
}
|
|
stmt = stmt->next;
|
|
}
|
|
}
|
|
|
|
void SetVarUsage(Object *obj, Boolean noregister) {
|
|
VarInfo *vi;
|
|
CError_ASSERT(1875, obj->datatype != DALIAS);
|
|
|
|
if (obj->datatype == DLOCAL || obj->datatype == DNONLAZYPTR) {
|
|
vi = obj->u.var.info;
|
|
vi->used = 1;
|
|
if (!copts.global_optimizer) {
|
|
if (copts.optimize_for_size)
|
|
vi->usage++;
|
|
else
|
|
vi->usage += curstmtvalue;
|
|
}
|
|
|
|
if (noregister)
|
|
vi->noregister = 1;
|
|
}
|
|
}
|
|
|
|
static void checkexpression(ENode *expr) {
|
|
ENodeList *list;
|
|
|
|
while (1) {
|
|
switch (expr->type) {
|
|
case EOBJREF:
|
|
SetVarUsage(expr->data.objref, 1);
|
|
return;
|
|
case EINDIRECT:
|
|
if (ENODE_IS(expr->data.monadic, EOBJREF)) {
|
|
SetVarUsage(expr->data.monadic->data.objref, 0);
|
|
return;
|
|
}
|
|
expr = expr->data.monadic;
|
|
break;
|
|
case EFUNCCALL:
|
|
case EFUNCCALLP:
|
|
copt_isleaffunction = 0;
|
|
checkexpression(expr->data.funccall.funcref);
|
|
for (list = expr->data.funccall.args; list; list = list->next)
|
|
checkexpression(list->node);
|
|
return;
|
|
case ECOND:
|
|
case ECONDASS:
|
|
checkexpression(expr->data.cond.cond);
|
|
checkexpression(expr->data.cond.expr1);
|
|
checkexpression(expr->data.cond.expr2);
|
|
return;
|
|
case EMUL:
|
|
case EMULV:
|
|
case EDIV:
|
|
case EMODULO:
|
|
case EADDV:
|
|
case ESUBV:
|
|
case EADD:
|
|
case ESUB:
|
|
case ESHL:
|
|
case ESHR:
|
|
case ELESS:
|
|
case EGREATER:
|
|
case ELESSEQU:
|
|
case EGREATEREQU:
|
|
case EEQU:
|
|
case ENOTEQU:
|
|
case EAND:
|
|
case EXOR:
|
|
case EOR:
|
|
case ELAND:
|
|
case ELOR:
|
|
case EASS:
|
|
case EMULASS:
|
|
case EDIVASS:
|
|
case EMODASS:
|
|
case EADDASS:
|
|
case ESUBASS:
|
|
case ESHLASS:
|
|
case ESHRASS:
|
|
case EANDASS:
|
|
case EXORASS:
|
|
case EORASS:
|
|
case ECOMMA:
|
|
case EPMODULO:
|
|
case EROTL:
|
|
case EROTR:
|
|
case EBCLR:
|
|
case EBTST:
|
|
case EBSET:
|
|
checkexpression(expr->data.diadic.left);
|
|
expr = expr->data.diadic.right;
|
|
break;
|
|
case EPOSTINC:
|
|
case EPOSTDEC:
|
|
case EPREINC:
|
|
case EPREDEC:
|
|
case EMONMIN:
|
|
case EBINNOT:
|
|
case ELOGNOT:
|
|
case EFORCELOAD:
|
|
case ETYPCON:
|
|
case EBITFIELD:
|
|
expr = expr->data.monadic;
|
|
break;
|
|
case ENULLCHECK:
|
|
checkexpression(expr->data.nullcheck.nullcheckexpr);
|
|
expr = expr->data.nullcheck.condexpr;
|
|
break;
|
|
case EINTCONST:
|
|
case EFLOATCONST:
|
|
case EPRECOMP:
|
|
case ELABEL:
|
|
case EVECTOR128CONST:
|
|
return;
|
|
case ESTRINGCONST:
|
|
return;
|
|
default:
|
|
CError_FATAL(1998);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void checklocalusage(Statement *stmt) {
|
|
Statement *scan;
|
|
|
|
for (scan = stmt; scan; scan = scan->next) {
|
|
if (scan->type >= ST_EXPRESSION && scan->type <= ST_GOTOEXPR && scan->expr) {
|
|
curstmtvalue = scan->value;
|
|
checkexpression(scan->expr);
|
|
} else if (scan->type == ST_ASM) {
|
|
curstmtvalue = scan->value;
|
|
InlineAsm_CheckLocalUsage(scan);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void colorcode(Statement *stmt) {
|
|
CLabel *label;
|
|
SwitchCase *swcase;
|
|
|
|
while (stmt && !stmt->marked) {
|
|
stmt->marked = 1;
|
|
switch (stmt->type) {
|
|
case ST_GOTOEXPR:
|
|
return;
|
|
case ST_IFGOTO:
|
|
case ST_IFNGOTO:
|
|
case ST_OVF:
|
|
colorcode(stmt->label->stmt);
|
|
break;
|
|
case ST_GOTO:
|
|
case ST_EXIT:
|
|
stmt = stmt->label->stmt;
|
|
continue;
|
|
case ST_RETURN:
|
|
return;
|
|
case ST_SWITCH:
|
|
for (swcase = ((SwitchInfo *) stmt->label)->cases; swcase; swcase = swcase->next)
|
|
colorcode(swcase->label->stmt);
|
|
stmt = ((SwitchInfo *) stmt->label)->defaultlabel->stmt;
|
|
continue;
|
|
case ST_ASM:
|
|
if ((label = InlineAsm_GetReferencedLabel(stmt)))
|
|
colorcode(label->stmt);
|
|
if ((label = InlineAsm_GetReferencedLabel2(stmt)))
|
|
colorcode(label->stmt);
|
|
break;
|
|
case ST_ENDLOOP:
|
|
if (stmt->next && stmt->next->type == ST_GOTO) {
|
|
stmt = stmt->next;
|
|
stmt->marked = 1;
|
|
}
|
|
break;
|
|
case ST_NOP:
|
|
case ST_LABEL:
|
|
case ST_EXPRESSION:
|
|
case ST_ENTRY:
|
|
case ST_BEGINCATCH:
|
|
case ST_ENDCATCH:
|
|
case ST_ENDCATCHDTOR:
|
|
case ST_BEGINLOOP:
|
|
break;
|
|
default:
|
|
CError_FATAL(2096);
|
|
}
|
|
stmt = stmt->next;
|
|
}
|
|
}
|
|
|
|
static void removeunusedcode(Statement *stmt) {
|
|
Statement *scan;
|
|
|
|
for (scan = stmt; scan; scan = scan->next)
|
|
scan->marked = 0;
|
|
|
|
colorcode(stmt);
|
|
for (scan = stmt; scan; scan = scan->next) {
|
|
if (!scan->marked && (scan->flags & StmtFlag_1))
|
|
colorcode(scan);
|
|
}
|
|
|
|
for (scan = stmt; scan; scan = scan->next) {
|
|
if (!scan->marked && scan->type != ST_NOP) {
|
|
scan->type = ST_NOP;
|
|
stmtchanged = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void COpt_ReturnCheck(Object *obj, Statement *stmt) {
|
|
if ((copts.pedantic || copts.cplusplus) && obj && TYPE_FUNC(obj->type)->functype != &stvoid) {
|
|
while (stmt) {
|
|
if (!stmt->next && stmt->type != ST_GOTO && stmt->type != ST_RETURN) {
|
|
CError_Warning(CErrorStr184);
|
|
break;
|
|
}
|
|
|
|
if (stmt->type == ST_RETURN && !stmt->expr && !(stmt->flags & StmtFlag_8)) {
|
|
CError_Warning(CErrorStr184);
|
|
break;
|
|
}
|
|
|
|
stmt = stmt->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void COpt_Optimize(Object *obj, Statement *stmt) {
|
|
Statement **ptr;
|
|
|
|
do {
|
|
stmtchanged = 0;
|
|
optimizebranches(stmt->next);
|
|
removeunusedcode(stmt->next);
|
|
} while (stmtchanged);
|
|
|
|
ptr = &stmt->next;
|
|
while (*ptr) {
|
|
if ((*ptr)->type == ST_NOP)
|
|
*ptr = (*ptr)->next;
|
|
else
|
|
ptr = &(*ptr)->next;
|
|
}
|
|
}
|
|
|
|
static void COpt_ELABELCallBack(ENode *expr) {
|
|
CError_ASSERT(2195, expr->data.label->stmt && expr->data.label->stmt->type == ST_LABEL);
|
|
expr->data.label->stmt->flags |= StmtFlag_1;
|
|
}
|
|
|
|
void COpt_SimpleOptimizer(Object *obj, Statement *stmt) {
|
|
Statement *scan;
|
|
|
|
for (scan = stmt; scan; scan = scan->next) {
|
|
if ((scan->type >= ST_EXPRESSION && scan->type <= ST_GOTOEXPR) && scan->expr)
|
|
CExpr_SearchExprTree(scan->expr, COpt_ELABELCallBack, 1, ELABEL);
|
|
}
|
|
|
|
static_for_inlines = 1;
|
|
cleanreturnlabel = NULL;
|
|
COpt_Optimize(obj, stmt);
|
|
COpt_ReturnCheck(obj, stmt);
|
|
}
|
|
|
|
Statement *COpt_Optimizer(Object *obj, Statement *stmt) {
|
|
copt_isleaffunction = 1;
|
|
if (copts.global_optimizer)
|
|
stmt = IRO_Optimizer(obj, stmt);
|
|
|
|
static_for_inlines = 0;
|
|
COpt_Optimize(obj, stmt);
|
|
|
|
if (obj && !(obj->qual & Q_INLINE))
|
|
COpt_ReturnCheck(obj, stmt);
|
|
|
|
checklocalusage(stmt->next);
|
|
return stmt;
|
|
}
|