MWCC/compiler_and_linker/unsorted/IroCSE.c

1039 lines
33 KiB
C

#include "compiler/IroCSE.h"
#include "compiler/IroDump.h"
#include "compiler/IroFlowgraph.h"
#include "compiler/IroLinearForm.h"
#include "compiler/IroMalloc.h"
#include "compiler/IroPointerAnalysis.h"
#include "compiler/IroSubable.h"
#include "compiler/IROUseDef.h"
#include "compiler/IroUtil.h"
#include "compiler/IroVars.h"
#include "compiler/CError.h"
#include "compiler/CExpr.h"
#include "compiler/CInt64.h"
#include "compiler/CParser.h"
#include "compiler/CompilerTools.h"
#include "compiler/objects.h"
BitVector *IRO_Depends;
Boolean IRO_NotSubable;
Boolean IRO_IsVolatile;
Boolean IRO_CouldError;
IROExpr *IRO_FirstExpr;
IROExpr *IRO_LastExpr;
SInt32 IRO_NumExprs;
static Boolean HasVectorOperand;
// forward decls
static void IRO_DependsOnForDataFlow(IROLinear *linear, Boolean flag);
static void GetDependsOfIndirect(IROLinear *nd) {
IROListNode *resultList;
IROListNode *next;
IROListNode *list;
IROListNode *scan;
IROLinear *scannd;
Object *obj;
VarRecord *var;
int index;
Boolean result;
Boolean foundObjRef;
result = 0;
if (nd && copts.opt_pointer_analysis && nd->pointsToFunction && FunctionName) {
resultList = NULL;
PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, nd, &resultList);
if ((list = resultList)) {
for (scan = list; scan; scan = scan->nextList) {
if (!scan->list.head || !scan->list.tail) {
result = 1;
break;
}
foundObjRef = 0;
for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
foundObjRef = 1;
break;
}
}
if (!foundObjRef) {
result = 1;
break;
}
}
if (!result) {
while (list) {
for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
obj = scannd->u.node->data.objref;
CError_ASSERT(119, obj != NULL);
var = IRO_FindVar(obj, 1, 1);
CError_ASSERT(121, var != NULL);
index = var->index;
CError_ASSERT(123, index != 0);
if (is_volatile_object(obj)) {
IRO_IsVolatile = 1;
IRO_NotSubable = 1;
}
Bv_SetBit(index, IRO_Depends);
}
}
list = list->nextList;
}
}
while (resultList) {
next = resultList->nextList;
IRO_free(resultList);
resultList = next;
}
} else {
result = 1;
}
} else {
result = 1;
}
if (result) {
nd = nd->u.monadic;
if (nd->type == IROLinearOp1Arg && nd->nodetype == EBITFIELD)
nd = nd->u.monadic;
if (nd->type == IROLinearOp2Arg && nd->nodetype == EADD) {
IRO_BaseTerms = 0;
IRO_VarTerms = 0;
IRO_DecomposeAddressExpression_Cheap(nd);
if (IRO_BaseTerms != 1) {
IRO_CouldError = 1;
Bv_SetBit(0, IRO_Depends);
Bv_Or(IRO_FuncKills, IRO_Depends);
}
if (IRO_VarTerms)
IRO_CouldError = 1;
} else {
IRO_CouldError = 1;
Bv_SetBit(0, IRO_Depends);
Bv_Or(IRO_FuncKills, IRO_Depends);
}
}
}
static void GetDependsOfFunctionCallForDataFlow(IROLinear *nd) {
IROLinear *innernd;
IROListNode *resultList;
IROListNode *next;
IROListNode *list;
IROListNode *scan;
IROLinear *scannd;
Object *obj;
VarRecord *var;
int index;
Boolean result;
Boolean foundObjRef;
ObjectList *olist;
ObjectList *depsList;
result = 0;
innernd = nd->u.funccall.linear8;
if (innernd && copts.opt_pointer_analysis && innernd->pointsToFunction && FunctionName) {
resultList = NULL;
PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, innernd, &resultList);
if ((list = resultList)) {
for (scan = list; scan; scan = scan->nextList) {
if (!scan->list.head || !scan->list.tail) {
result = 1;
break;
}
foundObjRef = 0;
for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
foundObjRef = 1;
obj = scannd->u.node->data.objref;
CError_ASSERT(234, obj != NULL);
depsList = NULL;
PointerAnalysis_GetFunctionDependencies(obj, nd, &depsList);
for (olist = depsList; olist; olist = olist->next) {
if (!olist->object) {
result = 1;
break;
}
}
while (depsList) {
olist = depsList->next;
IRO_free(depsList);
depsList = olist;
}
if (result)
break;
}
}
if (!foundObjRef)
result = 1;
if (result)
break;
}
if (!result) {
for (list = resultList; list; list = list->nextList) {
for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
obj = scannd->u.node->data.objref;
depsList = NULL;
PointerAnalysis_GetFunctionDependencies(obj, nd, &depsList);
for (olist = depsList; olist; olist = olist->next) {
var = IRO_FindVar(olist->object, 1, 1);
CError_ASSERT(285, var != NULL);
index = var->index;
CError_ASSERT(287, index != 0);
if (is_volatile_object(olist->object)) {
IRO_IsVolatile = 1;
IRO_NotSubable = 1;
}
Bv_SetBit(index, IRO_Depends);
}
while (depsList) {
olist = depsList->next;
IRO_free(depsList);
depsList = olist;
}
}
}
}
}
while (resultList) {
next = resultList->nextList;
IRO_free(resultList);
resultList = next;
}
} else {
result = 1;
}
} else {
result = 1;
}
if (result) {
IRO_DependsOnForDataFlow(nd->u.funccall.linear8, 0);
Bv_Or(IRO_FuncKills, IRO_Depends);
for (index = nd->u.funccall.argCount - 1; index >= 0; index--)
IRO_DependsOnForDataFlow(nd->u.funccall.args[index], 0);
}
}
static void IRO_DependsOn(IROLinear *linear, Boolean flag) {
VarRecord *var;
IROLinear *inner;
if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) {
IRO_IsVolatile = 1;
IRO_NotSubable = 1;
}
if (!IRO_NotSubable) {
switch (linear->type) {
case IROLinearOperand:
if (flag && linear->u.node->type == EOBJREF) {
if ((var = IRO_FindVar(linear->u.node->data.objref, 0, 1))) {
if (is_volatile_object(var->object)) {
IRO_IsVolatile = 1;
IRO_NotSubable = 1;
}
Bv_SetBit(var->index, IRO_Depends);
} else {
IRO_NotSubable = 1;
}
}
break;
case IROLinearOp1Arg:
if (IRO_IsAssignOp[linear->nodetype]) {
IRO_NotSubable = 1;
} else {
inner = linear->u.monadic;
if (linear->nodetype == EINDIRECT) {
if (inner->type == IROLinearOp1Arg && inner->nodetype == EBITFIELD)
inner = inner->u.monadic;
if (inner->type != IROLinearOperand || inner->u.node->type != EOBJREF)
GetDependsOfIndirect(linear);
}
IRO_DependsOn(inner, linear->nodetype == EINDIRECT);
}
break;
case IROLinearOp2Arg:
if (IRO_IsAssignOp[linear->nodetype]) {
IRO_NotSubable = 1;
} else {
if (linear->nodetype == EDIV || linear->nodetype == EMODULO) {
if (IRO_IsIntConstant(linear->u.diadic.right)) {
if (CInt64_Equal(linear->u.diadic.right->u.node->data.intval, cint64_zero))
IRO_CouldError = 1;
} else {
IRO_CouldError = 1;
}
}
IRO_DependsOn(linear->u.diadic.left, flag);
IRO_DependsOn(linear->u.diadic.right, flag);
}
break;
case IROLinearOp3Arg:
if (IRO_IsAssignOp[linear->nodetype]) {
IRO_NotSubable = 1;
} else {
IRO_DependsOn(linear->u.args3.a, flag);
IRO_DependsOn(linear->u.args3.b, flag);
IRO_DependsOn(linear->u.args3.c, flag);
}
break;
case IROLinearFunccall:
IRO_NotSubable = 1;
break;
default:
CError_FATAL(479);
}
}
}
static void IRO_DependsOnForDataFlow(IROLinear *linear, Boolean flag) {
VarRecord *var;
IROLinear *inner;
if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) {
IRO_IsVolatile = 1;
IRO_NotSubable = 1;
}
switch (linear->type) {
case IROLinearOperand:
if (flag && linear->u.node->type == EOBJREF) {
if ((var = IRO_FindVar(linear->u.node->data.objref, 0, 1))) {
if (is_volatile_object(var->object)) {
IRO_IsVolatile = 1;
IRO_NotSubable = 1;
}
Bv_SetBit(var->index, IRO_Depends);
} else {
IRO_NotSubable = 1;
}
}
break;
case IROLinearOp1Arg:
if (IRO_IsAssignOp[linear->nodetype])
IRO_NotSubable = 1;
inner = linear->u.monadic;
if (linear->nodetype == EINDIRECT) {
if (inner->type == IROLinearOp1Arg && inner->nodetype == EBITFIELD)
inner = inner->u.monadic;
if (inner->type != IROLinearOperand || inner->u.node->type != EOBJREF)
GetDependsOfIndirect(linear);
}
IRO_DependsOnForDataFlow(inner, linear->nodetype == EINDIRECT);
break;
case IROLinearOp2Arg:
if (IRO_IsAssignOp[linear->nodetype])
IRO_NotSubable = 1;
if (linear->nodetype == EDIV || linear->nodetype == EMODULO) {
if (IRO_IsIntConstant(linear->u.diadic.right)) {
if (CInt64_Equal(linear->u.diadic.right->u.node->data.intval, cint64_zero))
IRO_CouldError = 1;
} else {
IRO_CouldError = 1;
}
}
IRO_DependsOnForDataFlow(linear->u.diadic.left, flag);
IRO_DependsOnForDataFlow(linear->u.diadic.right, flag);
break;
case IROLinearOp3Arg:
if (IRO_IsAssignOp[linear->nodetype])
IRO_NotSubable = 1;
IRO_DependsOnForDataFlow(linear->u.args3.a, flag);
IRO_DependsOnForDataFlow(linear->u.args3.b, flag);
IRO_DependsOnForDataFlow(linear->u.args3.c, flag);
break;
case IROLinearFunccall:
IRO_NotSubable = 1;
GetDependsOfFunctionCallForDataFlow(linear);
break;
default:
CError_FATAL(650);
}
}
void IRO_FindDepends_NoAlloc(IROLinear *linear) {
Bv_Clear(IRO_Depends);
IRO_CouldError = 0;
IRO_NotSubable = 0;
IRO_IsVolatile = 0;
IRO_DependsOnForDataFlow(linear, 0);
}
void IRO_FindDepends(IROLinear *linear) {
Bv_AllocVector(&IRO_Depends, IRO_NumVars + 1);
IRO_CouldError = 0;
IRO_NotSubable = 0;
IRO_DependsOn(linear, 0);
}
static void VecAct(IROLinear *linear, Boolean isFirst) {
if (!isFirst && (linear->flags & IROLF_VecOpBase))
HasVectorOperand = 1;
}
static Boolean IRO_DoesNotHaveVectorOperand(IROLinear *linear) {
HasVectorOperand = 0;
IRO_WalkTree(linear, VecAct);
return HasVectorOperand == 0;
}
static void IRO_AddExpression(IROLinear *linear, IRONode *node, Boolean flag) {
IROExpr *expr;
if ((linear->flags & IROLF_Reffed) && IRO_IsSubableExpression(linear) && IRO_DoesNotHaveVectorOperand(linear)) {
expr = oalloc(sizeof(IROExpr));
expr->x0 = 0;
expr->index = ++IRO_NumExprs;
expr->linear = linear;
expr->x8 = NULL;
expr->node = node;
IRO_FindDepends(linear);
expr->depends = IRO_Depends;
expr->notSubable = IRO_NotSubable;
expr->couldError = IRO_CouldError;
expr->next = NULL;
expr->x14 = NULL;
if (IRO_FirstExpr)
IRO_LastExpr->next = expr;
else
IRO_FirstExpr = expr;
IRO_LastExpr = expr;
linear->expr = expr;
}
}
void IRO_FindExpressions(BitVector *bv, Boolean flag) {
IROLinear *nd;
IRONode *fnode;
IRO_FirstExpr = IRO_LastExpr = NULL;
IRO_NumExprs = 0;
for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
if (!bv || Bv_IsBitSet(fnode->index, bv)) {
for (nd = fnode->first; nd; nd = nd->next) {
nd->expr = NULL;
IRO_AddExpression(nd, fnode, flag);
if (nd == fnode->last)
break;
}
} else {
for (nd = fnode->first; nd; nd = nd->next) {
nd->expr = NULL;
if (nd == fnode->last)
break;
}
}
}
IRO_CheckForUserBreak();
}
void IRO_RemoveExpr(IROExpr *expr) {
IROExpr *prev;
IROExpr *scan;
scan = IRO_FirstExpr;
prev = NULL;
while (scan != expr) {
prev = scan;
scan = scan->next;
CError_ASSERT(809, scan);
}
expr->linear->expr = NULL;
if (prev)
prev->next = expr->next;
else
IRO_FirstExpr = expr->next;
}
static void GetExprKillsByIndirectAssignment(IROLinear *linear) {
IROLinear *inner;
IROListNode *resultList;
IROListNode *next;
IROListNode *list;
IROListNode *scan;
IROLinear *scannd;
Object *obj;
VarRecord *var;
int index;
Boolean result;
Boolean foundObjRef;
IROExpr *expr;
result = 0;
if (linear->type == IROLinearOp2Arg)
linear = linear->u.diadic.left;
else
linear = linear->u.monadic;
if (
linear &&
linear->type == IROLinearOp1Arg &&
linear->nodetype == EINDIRECT &&
(inner = linear->u.monadic) &&
copts.opt_pointer_analysis &&
inner->pointsToFunction &&
FunctionName
) {
resultList = NULL;
PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, inner, &resultList);
if ((list = resultList)) {
for (scan = list; scan; scan = scan->nextList) {
if (!scan->list.head || !scan->list.tail) {
result = 1;
break;
}
foundObjRef = 0;
for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
foundObjRef = 1;
break;
}
}
if (!foundObjRef) {
result = 1;
break;
}
}
if (!result) {
while (list) {
for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
obj = scannd->u.node->data.objref;
CError_ASSERT(893, obj != NULL);
var = IRO_FindVar(obj, 1, 1);
CError_ASSERT(895, var != NULL);
index = var->index;
for (expr = IRO_FirstExpr; expr; expr = expr->next) {
if (Bv_IsBitSet(index, expr->depends))
Bv_SetBit(expr->index, IRO_ExprKills);
}
}
}
list = list->nextList;
}
}
while (resultList) {
next = resultList->nextList;
IRO_free(resultList);
resultList = next;
}
} else {
result = 1;
}
} else {
result = 1;
}
if (result) {
for (expr = IRO_FirstExpr; expr; expr = expr->next) {
if (Bv_BitsInCommon(expr->depends, IRO_FuncKills))
Bv_SetBit(expr->index, IRO_ExprKills);
}
}
}
static void GetExprKillsByFunctionCall(IROLinear *funccall) {
IROLinear *innernd;
IROListNode *resultList;
IROListNode *next;
IROListNode *list;
IROListNode *scan;
IROLinear *scannd;
Object *obj;
VarRecord *var;
int index;
Boolean result;
Boolean foundObjRef;
ObjectList *olist;
ObjectList *depsList;
IROExpr *expr;
result = 0;
innernd = funccall->u.funccall.linear8;
if (innernd && copts.opt_pointer_analysis && innernd->pointsToFunction && FunctionName) {
resultList = NULL;
PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, innernd, &resultList);
if ((list = resultList)) {
for (scan = list; scan; scan = scan->nextList) {
if (!scan->list.head || !scan->list.tail) {
result = 1;
break;
}
foundObjRef = 0;
for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
foundObjRef = 1;
obj = scannd->u.node->data.objref;
CError_ASSERT(991, obj != NULL);
depsList = NULL;
PointerAnalysis_GetFunctionKills(obj, funccall, &depsList);
for (olist = depsList; olist; olist = olist->next) {
if (!olist->object) {
result = 1;
break;
}
}
while (depsList) {
olist = depsList->next;
IRO_free(depsList);
depsList = olist;
}
if (result)
break;
}
}
if (!foundObjRef)
result = 1;
if (result)
break;
}
if (!result) {
for (list = resultList; list; list = list->nextList) {
for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
obj = scannd->u.node->data.objref;
depsList = NULL;
PointerAnalysis_GetFunctionKills(obj, funccall, &depsList);
for (olist = depsList; olist; olist = olist->next) {
var = IRO_FindVar(olist->object, 1, 1);
CError_ASSERT(1042, var != NULL);
index = var->index;
CError_ASSERT(1044, index != 0);
for (expr = IRO_FirstExpr; expr; expr = expr->next) {
if (Bv_IsBitSet(index, expr->depends))
Bv_SetBit(expr->index, IRO_ExprKills);
}
}
while (depsList) {
olist = depsList->next;
IRO_free(depsList);
depsList = olist;
}
}
}
}
}
while (resultList) {
next = resultList->nextList;
IRO_free(resultList);
resultList = next;
}
} else {
result = 1;
}
} else {
result = 1;
}
if (result) {
for (expr = IRO_FirstExpr; expr; expr = expr->next) {
if (Bv_BitsInCommon(expr->depends, IRO_FuncKills))
Bv_SetBit(expr->index, IRO_ExprKills);
}
}
}
static void IRO_GetExprKills(IROLinear *linear) {
Bv_Clear(IRO_ExprKills);
switch (linear->type) {
case IROLinearOp1Arg:
case IROLinearOp2Arg:
if (IRO_IsAssignOp[linear->nodetype]) {
VarRecord *var;
int index;
var = IRO_FindAssigned(linear);
index = 0;
if (var)
index = var->index;
if (!index) {
GetExprKillsByIndirectAssignment(linear);
} else {
IROExpr *expr;
for (expr = IRO_FirstExpr; expr; expr = expr->next) {
if (Bv_IsBitSet(index, expr->depends))
Bv_SetBit(expr->index, IRO_ExprKills);
}
}
}
break;
case IROLinearAsm: {
IROExpr *expr;
IRO_GetKills(linear);
for (expr = IRO_FirstExpr; expr; expr = expr->next) {
if (Bv_BitsInCommon(expr->depends, IRO_VarKills))
Bv_SetBit(expr->index, IRO_ExprKills);
}
break;
}
case IROLinearFunccall:
GetExprKillsByFunctionCall(linear);
break;
}
}
void IRO_ComputeAvail(void) {
IRONode *node;
IROLinear *linear;
SInt32 counter;
BitVector *bv;
Boolean flag;
counter = 0;
node = IRO_FirstNode;
Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
Bv_AllocVector(&IRO_ExprKills, IRO_NumExprs + 1);
while (node) {
Bv_AllocVector(&node->x16, IRO_NumExprs);
if (node->numpred)
Bv_Set(node->x16);
Bv_AllocVector(&node->x22, IRO_NumExprs);
Bv_AllocVector(&node->x1E, IRO_NumExprs);
Bv_AllocVector(&node->x1A, IRO_NumExprs);
for (linear = node->first; linear; linear = linear->next) {
if (linear->expr)
Bv_SetBit(linear->expr->index, node->x1E);
IRO_GetExprKills(linear);
Bv_Or(IRO_ExprKills, node->x22);
Bv_Minus(IRO_ExprKills, node->x1E);
if (linear == node->last)
break;
if (counter > 250) {
IRO_CheckForUserBreak();
counter = 0;
} else {
counter++;
}
}
Bv_Copy(node->x16, node->x1A);
Bv_Minus(node->x22, node->x1A);
Bv_Or(node->x1E, node->x1A);
node = node->nextnode;
}
IRO_CheckForUserBreak();
Bv_AllocVector(&bv, IRO_NumExprs);
do {
flag = 0;
for (node = IRO_FirstNode; node; node = node->nextnode) {
if (!node->numpred) {
Bv_Clear(bv);
} else {
UInt16 i;
Bv_Set(bv);
for (i = 0; i < node->numpred; i++)
Bv_And(IRO_NodeTable[node->pred[i]]->x1A, bv);
}
if (!Bv_Compare(bv, node->x16)) {
flag = 1;
Bv_Copy(bv, node->x16);
}
Bv_Copy(node->x16, node->x1A);
Bv_Minus(node->x22, node->x1A);
Bv_Or(node->x1E, node->x1A);
}
IRO_CheckForUserBreak();
} while (flag);
}
static void IRO_MakeReplacementEmbedded(IROExpr *expr) {
IROLinear *opnd;
IROLinear *ind;
IROLinear *ass;
IRO_GetTemp(expr);
opnd = IRO_NewLinear(IROLinearOperand);
opnd->u.node = create_objectrefnode(expr->x8);
opnd->rtype = opnd->u.node->data.objref->type;
opnd->index = ++IRO_NumLinear;
opnd->flags |= IROLF_Reffed | IROLF_Assigned | IROLF_Ind;
ind = IRO_NewLinear(IROLinearOp1Arg);
ind->nodetype = EINDIRECT;
ind->rtype = expr->linear->rtype;
ind->u.monadic = opnd;
ind->index = ++IRO_NumLinear;
ind->flags |= IROLF_Reffed | IROLF_Assigned;
ass = IRO_NewLinear(IROLinearOp2Arg);
ass->nodetype = EASS;
ass->u.diadic.left = ind;
ass->u.diadic.right = expr->linear;
ass->rtype = expr->linear->rtype;
ass->index = ++IRO_NumLinear;
opnd->next = ind;
ind->next = ass;
IRO_ReplaceReferenceWithNode(expr->linear, ass);
IRO_PasteAfter(opnd, ass, expr->linear);
}
static void IRO_ActUnmarkSubExpressions(IROLinear *linear, Boolean isFirst) {
if (isFirst)
linear->flags &= ~IROLF_8;
}
static void CheckCommonSub(IROLinear *linear) {
IROExpr *expr;
for (expr = IRO_FirstExpr; expr; expr = expr->next) {
if (expr->linear != linear && !expr->x14) {
if (Bv_IsBitSet(expr->index, IRO_Avail) && !expr->notSubable && IRO_ExprsSame(linear, expr->linear)) {
IRO_WalkTree(linear, IRO_ActUnmarkSubExpressions);
linear->flags |= IROLF_8;
linear->expr->x14 = expr;
break;
}
}
}
}
static void MoveCommonSub(IROExpr *expr) {
SInt32 best;
SInt32 sz1;
SInt32 sz2;
SInt32 i1;
SInt32 i2;
IROLinear *scan;
IROLinear *array1[64];
IROLinear *array2[64];
IROExpr *scanexpr;
sz1 = 0;
scan = expr->linear;
do {
scan = IRO_LocateFather(scan);
if (scan) {
if (sz1 == 64)
return;
array1[sz1++] = scan;
}
} while (scan);
best = -1;
for (scanexpr = IRO_FirstExpr; scanexpr; scanexpr = scanexpr->next) {
if (scanexpr->x14 == expr) {
sz2 = 0;
scan = scanexpr->linear;
do {
scan = IRO_LocateFather(scan);
if (scan) {
if (sz2 == 64)
return;
array2[sz2++] = scan;
}
} while (scan);
i1 = sz1;
i2 = sz2;
while (i1 && i2 && array1[sz1 - 1] == array2[sz2 - 1]) {
i1--;
i2--;
}
if (i1 != sz1 && i1 > best)
best = i1;
}
}
if (best < 0) {
IRO_MakeReplacementEmbedded(expr);
} else {
IROLinear *start;
IROLinear *comma;
IRO_Dump("Moving common sub from node %d to %d\n", expr->linear->index, array1[best]->index);
start = IRO_FindStart(array1[best]);
IRO_GetTemp(expr);
IRO_ReplaceReference(expr->linear, expr->x8, expr->linear);
IRO_MoveExpression(expr, start);
comma = IRO_NewLinear(IROLinearOp2Arg);
comma->nodetype = ECOMMA;
comma->rtype = array1[best]->rtype;
comma->u.diadic.left = IRO_AssignToTemp(expr);
comma->u.diadic.right = array1[best];
comma->stmt = array1[best]->stmt;
IRO_ReplaceReferenceWithNode(array1[best], comma);
IRO_PasteAfter(comma, comma, array1[best]);
}
}
static void ReplaceCommonSub(IROLinear *linear) {
IROExpr *expr = linear->expr->x14;
if (!expr->x8) {
MoveCommonSub(expr);
if (!expr->x8)
return;
}
IRO_Dump("Replacing common sub at %d with %d\n", linear->index, expr->linear->index);
IRO_ReplaceReference(linear, expr->x8, linear);
IRO_RemoveExpr(linear->expr);
IRO_NopOut(linear);
}
void IRO_CommonSubs(void) {
IRONode *node;
IROLinear *linear;
SInt32 counter;
counter = 0;
for (node = IRO_FirstNode; node; node = node->nextnode) {
IRO_Avail = node->x16;
linear = node->first;
while (1) {
if (!linear)
break;
if (linear->expr && !linear->expr->notSubable)
CheckCommonSub(linear);
if (linear->expr)
Bv_SetBit(linear->expr->index, IRO_Avail);
IRO_GetExprKills(linear);
Bv_Minus(IRO_ExprKills, IRO_Avail);
if (linear == node->last)
break;
if (counter > 250) {
IRO_CheckForUserBreak();
counter = 0;
} else {
counter++;
}
linear = linear->next;
}
}
for (node = IRO_FirstNode; node; node = node->nextnode) {
for (linear = node->first; linear; linear = linear->next) {
if (linear->expr && (linear->flags & IROLF_8) && !IRO_HasSideEffect(linear))
ReplaceCommonSub(linear);
if (linear == node->last)
break;
if (counter > 250) {
IRO_CheckForUserBreak();
counter = 0;
} else {
counter++;
}
}
}
IRO_CheckForUserBreak();
}
static Boolean CountThisSubableOperandUse(IROUse *use) {
return use->x1C != 0;
}
static int GetSubableOperandUseCount(VarRecord *var) {
int count = 0;
IROUse *use;
if (var->uses) {
for (use = var->uses; use; use = use->varnext) {
if (CountThisSubableOperandUse(use))
count++;
}
}
return count;
}
static void IRO_MakeTopLevelExprForSubableOperand(IROLinear *linear) {
IROLinear *copy = IRO_NewLinear(IROLinearOperand);
memcpy(copy, linear, sizeof(IROLinear));
copy->index = ++IRO_NumLinear;
if (IRO_FirstLinear && IRO_FirstLinear->type == IROLinearNop)
IRO_PasteAfter(copy, copy, IRO_FirstLinear);
else
IRO_Paste(copy, copy, IRO_FirstLinear);
}
void IRO_GenerateTopLevelExprsForSubableOperands(void) {
IROLinear *nd;
IRONode *fnode;
VarRecord *var;
BitVector *bv;
Bv_AllocVector(&bv, IRO_NumVars + 1);
for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
for (nd = fnode->first; nd; nd = nd->next) {
nd->expr = NULL;
if ((nd->flags & IROLF_Reffed) && IRO_IsSubableExpression(nd) && IRO_DoesNotHaveVectorOperand(nd)) {
if (nd->type == IROLinearOperand && nd->u.node && nd->u.node->type == EOBJREF) {
if ((var = IRO_FindVar(nd->u.node->data.objref, 0, 1))) {
if (!Bv_IsBitSet(var->index, bv)) {
IRO_MakeTopLevelExprForSubableOperand(nd);
Bv_SetBit(var->index, bv);
}
}
}
}
if (nd == fnode->last)
break;
}
}
}