mirror of https://git.wuffs.org/MWCC
915 lines
31 KiB
C
915 lines
31 KiB
C
#include "compiler/IroEval.h"
|
|
#include "compiler/CInt64.h"
|
|
#include "compiler/CMachine.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/IroFlowgraph.h"
|
|
#include "compiler/IroLinearForm.h"
|
|
#include "compiler/IroMalloc.h"
|
|
#include "compiler/IroPointerAnalysis.h"
|
|
#include "compiler/IroUtil.h"
|
|
#include "compiler/IroVars.h"
|
|
#include "compiler/enode.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler/types.h"
|
|
|
|
static Boolean IsAssociativeENodeType[MAXEXPR];
|
|
|
|
void IRO_InitializeIsAssociativeENodeTypeArray(void) {
|
|
int i;
|
|
|
|
for (i = 0; i < MAXEXPR; i++)
|
|
IsAssociativeENodeType[i] = 0;
|
|
|
|
IsAssociativeENodeType[EPOSTINC] = 0;
|
|
IsAssociativeENodeType[EPOSTDEC] = 0;
|
|
IsAssociativeENodeType[EPREINC] = 0;
|
|
IsAssociativeENodeType[EPREDEC] = 0;
|
|
IsAssociativeENodeType[EINDIRECT] = 0;
|
|
IsAssociativeENodeType[EMONMIN] = 0;
|
|
IsAssociativeENodeType[EBINNOT] = 0;
|
|
IsAssociativeENodeType[ELOGNOT] = 0;
|
|
IsAssociativeENodeType[EFORCELOAD] = 0;
|
|
IsAssociativeENodeType[EMUL] = 1;
|
|
IsAssociativeENodeType[EMULV] = 1;
|
|
IsAssociativeENodeType[EDIV] = 0;
|
|
IsAssociativeENodeType[EMODULO] = 0;
|
|
IsAssociativeENodeType[EADDV] = 1;
|
|
IsAssociativeENodeType[ESUBV] = 0;
|
|
IsAssociativeENodeType[EADD] = 1;
|
|
IsAssociativeENodeType[ESUB] = 0;
|
|
IsAssociativeENodeType[ESHL] = 0;
|
|
IsAssociativeENodeType[ESHR] = 0;
|
|
IsAssociativeENodeType[ELESS] = 0;
|
|
IsAssociativeENodeType[EGREATER] = 0;
|
|
IsAssociativeENodeType[ELESSEQU] = 0;
|
|
IsAssociativeENodeType[EGREATEREQU] = 0;
|
|
IsAssociativeENodeType[EEQU] = 0;
|
|
IsAssociativeENodeType[ENOTEQU] = 0;
|
|
IsAssociativeENodeType[EAND] = 1;
|
|
IsAssociativeENodeType[EXOR] = 1;
|
|
IsAssociativeENodeType[EOR] = 1;
|
|
IsAssociativeENodeType[ELAND] = 0;
|
|
IsAssociativeENodeType[ELOR] = 0;
|
|
IsAssociativeENodeType[EASS] = 0;
|
|
IsAssociativeENodeType[EMULASS] = 0;
|
|
IsAssociativeENodeType[EDIVASS] = 0;
|
|
IsAssociativeENodeType[EMODASS] = 0;
|
|
IsAssociativeENodeType[EADDASS] = 0;
|
|
IsAssociativeENodeType[ESUBASS] = 0;
|
|
IsAssociativeENodeType[ESHLASS] = 0;
|
|
IsAssociativeENodeType[ESHRASS] = 0;
|
|
IsAssociativeENodeType[EANDASS] = 0;
|
|
IsAssociativeENodeType[EXORASS] = 0;
|
|
IsAssociativeENodeType[EORASS] = 0;
|
|
IsAssociativeENodeType[ECOMMA] = 0;
|
|
IsAssociativeENodeType[EPMODULO] = 0;
|
|
IsAssociativeENodeType[EROTL] = 0;
|
|
IsAssociativeENodeType[EROTR] = 0;
|
|
IsAssociativeENodeType[EBCLR] = 0;
|
|
IsAssociativeENodeType[EBTST] = 0;
|
|
IsAssociativeENodeType[EBSET] = 0;
|
|
IsAssociativeENodeType[ETYPCON] = 0;
|
|
IsAssociativeENodeType[EBITFIELD] = 0;
|
|
IsAssociativeENodeType[EINTCONST] = 0;
|
|
IsAssociativeENodeType[EFLOATCONST] = 0;
|
|
IsAssociativeENodeType[ESTRINGCONST] = 0;
|
|
IsAssociativeENodeType[ECOND] = 0;
|
|
IsAssociativeENodeType[EFUNCCALL] = 0;
|
|
IsAssociativeENodeType[EFUNCCALLP] = 0;
|
|
IsAssociativeENodeType[EOBJREF] = 0;
|
|
IsAssociativeENodeType[EMFPOINTER] = 0;
|
|
IsAssociativeENodeType[ENULLCHECK] = 0;
|
|
IsAssociativeENodeType[EPRECOMP] = 0;
|
|
IsAssociativeENodeType[ETEMP] = 0;
|
|
IsAssociativeENodeType[EARGOBJ] = 0;
|
|
IsAssociativeENodeType[ELOCOBJ] = 0;
|
|
IsAssociativeENodeType[ELABEL] = 0;
|
|
IsAssociativeENodeType[ESETCONST] = 0;
|
|
IsAssociativeENodeType[ENEWEXCEPTION] = 0;
|
|
IsAssociativeENodeType[ENEWEXCEPTIONARRAY] = 0;
|
|
IsAssociativeENodeType[EOBJLIST] = 0;
|
|
IsAssociativeENodeType[EMEMBER] = 0;
|
|
IsAssociativeENodeType[ETEMPLDEP] = 0;
|
|
IsAssociativeENodeType[EINSTRUCTION] = 0;
|
|
IsAssociativeENodeType[EDEFINE] = 0;
|
|
IsAssociativeENodeType[EREUSE] = 0;
|
|
IsAssociativeENodeType[EASSBLK] = 0;
|
|
IsAssociativeENodeType[EVECTOR128CONST] = 0;
|
|
IsAssociativeENodeType[ECONDASS] = 0;
|
|
}
|
|
|
|
void IRO_TruncateValueToType(CInt64 *val, Type *type) {
|
|
if (IRO_IsUnsignedType(type)) {
|
|
switch (type->size) {
|
|
case 1:
|
|
CInt64_ConvertUInt8(val);
|
|
break;
|
|
case 2:
|
|
CInt64_ConvertUInt16(val);
|
|
break;
|
|
case 4:
|
|
CInt64_ConvertUInt32(val);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (type->size) {
|
|
case 1:
|
|
CInt64_ConvertInt8(val);
|
|
break;
|
|
case 2:
|
|
CInt64_ConvertInt16(val);
|
|
break;
|
|
case 4:
|
|
CInt64_ConvertInt32(val);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void IRO_TruncateBitfieldValueToType(CInt64 *val, Type *type, Type *type2) {
|
|
UInt32 limit;
|
|
UInt32 i;
|
|
UInt32 j;
|
|
CInt64 work;
|
|
|
|
work = cint64_zero;
|
|
limit = TYPE_BITFIELD(type2)->unkB;
|
|
for (i = 0; i < limit; i++)
|
|
work = CInt64_Or(work, CInt64_Shl(cint64_one, IRO_MakeULong(i)));
|
|
*val = CInt64_And(*val, work);
|
|
|
|
if (!IRO_IsUnsignedType(type)) {
|
|
work = cint64_zero;
|
|
for (j = 0; j <= (i - 1); j++) {
|
|
if (j == (i - 1))
|
|
work = CInt64_Or(work, CInt64_Shl(cint64_one, IRO_MakeULong(j)));
|
|
}
|
|
if (CInt64_NotEqual(CInt64_And(work, *val), cint64_zero)) {
|
|
for (j = i - 1; j < 64; j++)
|
|
*val = CInt64_Or(*val, CInt64_Shl(cint64_one, IRO_MakeULong(j)));
|
|
}
|
|
}
|
|
|
|
IRO_TruncateValueToType(val, type);
|
|
}
|
|
|
|
void IRO_ConstantFolding(void) {
|
|
IROLinear *nd;
|
|
ENode *expr;
|
|
int isCompare;
|
|
int flag;
|
|
CInt64 val;
|
|
|
|
for (nd = IRO_FirstLinear; nd; nd = nd->next) {
|
|
switch (nd->type) {
|
|
case IROLinearOp1Arg:
|
|
if (IRO_IsIntConstant(nd->u.monadic)) {
|
|
expr = NULL;
|
|
flag = 0;
|
|
val = nd->u.monadic->u.node->data.intval;
|
|
if (nd->nodetype == ETYPCON && IS_TYPE_FLOAT(nd->rtype)) {
|
|
expr = IRO_NewENode(EFLOATCONST);
|
|
if (!IRO_IsUnsignedType(nd->u.monadic->rtype))
|
|
expr->data.floatval.value = CInt64_ConvertToLongDouble(&val);
|
|
else
|
|
expr->data.floatval.value = CInt64_ConvertUToLongDouble(&val);
|
|
expr->rtype = nd->rtype;
|
|
} else {
|
|
switch (nd->nodetype) {
|
|
case ETYPCON:
|
|
flag = 1;
|
|
break;
|
|
case ELOGNOT:
|
|
val = CInt64_Not(val);
|
|
flag = 1;
|
|
break;
|
|
case EBINNOT:
|
|
val = CInt64_Inv(val);
|
|
flag = 1;
|
|
break;
|
|
case EMONMIN:
|
|
val = CInt64_Neg(val);
|
|
flag = 1;
|
|
break;
|
|
}
|
|
|
|
if (flag) {
|
|
IRO_TruncateValueToType(&val, nd->rtype);
|
|
expr = IRO_NewENode(EINTCONST);
|
|
expr->rtype = nd->rtype;
|
|
expr->data.intval = val;
|
|
}
|
|
}
|
|
|
|
if (expr) {
|
|
nd->u.monadic->type = IROLinearNop;
|
|
nd->type = IROLinearOperand;
|
|
nd->u.node = expr;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IROLinearOp2Arg:
|
|
if (IRO_IsIntConstant(nd->u.diadic.left) && !IRO_IsIntConstant(nd->u.diadic.right) && IsAssociativeENodeType[nd->nodetype]) {
|
|
IROLinear *tmp = nd->u.diadic.right;
|
|
nd->u.diadic.right = nd->u.diadic.left;
|
|
nd->u.diadic.left = tmp;
|
|
}
|
|
|
|
if (IRO_IsIntConstant(nd->u.diadic.right) && nd->nodetype == ESUB) {
|
|
nd->nodetype = EADD;
|
|
if (IRO_IsIntConstant(nd->u.diadic.right)) {
|
|
CInt64 v;
|
|
v = CInt64_Neg(nd->u.diadic.right->u.node->data.intval);
|
|
nd->u.diadic.right->u.node->data.intval = v;
|
|
} else {
|
|
Float f;
|
|
f = CMach_CalcFloatMonadic(
|
|
nd->u.diadic.right->rtype,
|
|
'-',
|
|
nd->u.diadic.right->u.node->data.floatval);
|
|
nd->u.diadic.right->u.node->data.floatval = f;
|
|
}
|
|
}
|
|
|
|
if (
|
|
IRO_IsIntConstant(nd->u.diadic.right) &&
|
|
IsAssociativeENodeType[nd->nodetype] &&
|
|
nd->u.diadic.left->type == IROLinearOp2Arg &&
|
|
nd->u.diadic.left->nodetype == nd->nodetype &&
|
|
nd->u.diadic.left->rtype == nd->rtype &&
|
|
IRO_IsIntConstant(nd->u.diadic.left->u.diadic.right) &&
|
|
nd->u.diadic.left->u.diadic.right->rtype == nd->u.diadic.right->rtype
|
|
)
|
|
{
|
|
IROLinear *tmp = nd->u.diadic.left;
|
|
nd->u.diadic.left = tmp->u.diadic.left;
|
|
tmp->u.diadic.left = tmp->u.diadic.right;
|
|
tmp->u.diadic.right = nd->u.diadic.right;
|
|
tmp->rtype = tmp->u.diadic.left->rtype;
|
|
nd->u.diadic.right = tmp;
|
|
nd = tmp;
|
|
}
|
|
|
|
if (IRO_IsIntConstant(nd->u.diadic.left) && IRO_IsIntConstant(nd->u.diadic.right)) {
|
|
CInt64 val1 = nd->u.diadic.left->u.node->data.intval;
|
|
CInt64 val2 = nd->u.diadic.right->u.node->data.intval;
|
|
flag = 0;
|
|
switch (nd->nodetype) {
|
|
case EADD:
|
|
val = CInt64_Add(val1, val2);
|
|
flag = 1;
|
|
break;
|
|
case ESUB:
|
|
val = CInt64_Sub(val1, val2);
|
|
flag = 1;
|
|
break;
|
|
case EMUL:
|
|
if (IRO_IsUnsignedType(nd->rtype))
|
|
val = CInt64_MulU(val1, val2);
|
|
else
|
|
val = CInt64_Mul(val1, val2);
|
|
flag = 1;
|
|
break;
|
|
case EDIV:
|
|
if (!CInt64_IsZero(&val2)) {
|
|
if (IRO_IsUnsignedType(nd->rtype))
|
|
val = CInt64_DivU(val1, val2);
|
|
else
|
|
val = CInt64_Div(val1, val2);
|
|
flag = 1;
|
|
}
|
|
break;
|
|
case EMODULO:
|
|
if (!CInt64_IsZero(&val2)) {
|
|
if (IRO_IsUnsignedType(nd->rtype))
|
|
val = CInt64_ModU(val1, val2);
|
|
else
|
|
val = CInt64_Mod(val1, val2);
|
|
flag = 1;
|
|
}
|
|
break;
|
|
case ESHL:
|
|
val = CInt64_Shl(val1, val2);
|
|
flag = 1;
|
|
break;
|
|
case ESHR:
|
|
if (IRO_IsUnsignedType(nd->rtype))
|
|
val = CInt64_ShrU(val1, val2);
|
|
else
|
|
val = CInt64_Shr(val1, val2);
|
|
flag = 1;
|
|
break;
|
|
case EAND:
|
|
val = CInt64_And(val1, val2);
|
|
flag = 1;
|
|
break;
|
|
case EOR:
|
|
val = CInt64_Or(val1, val2);
|
|
flag = 1;
|
|
break;
|
|
case EXOR:
|
|
val = CInt64_Xor(val1, val2);
|
|
flag = 1;
|
|
break;
|
|
case ELESS:
|
|
if (IRO_IsUnsignedType(nd->u.diadic.left->rtype))
|
|
CInt64_SetULong(&val, CInt64_LessU(val1, val2));
|
|
else
|
|
CInt64_SetULong(&val, CInt64_Less(val1, val2));
|
|
flag = 1;
|
|
break;
|
|
case EGREATER:
|
|
if (IRO_IsUnsignedType(nd->u.diadic.left->rtype))
|
|
CInt64_SetULong(&val, CInt64_GreaterU(val1, val2));
|
|
else
|
|
CInt64_SetULong(&val, CInt64_Greater(val1, val2));
|
|
flag = 1;
|
|
break;
|
|
case ELESSEQU:
|
|
if (IRO_IsUnsignedType(nd->u.diadic.left->rtype))
|
|
CInt64_SetULong(&val, CInt64_LessEqualU(val1, val2));
|
|
else
|
|
CInt64_SetULong(&val, CInt64_LessEqual(val1, val2));
|
|
flag = 1;
|
|
break;
|
|
case EGREATEREQU:
|
|
if (IRO_IsUnsignedType(nd->u.diadic.left->rtype))
|
|
CInt64_SetULong(&val, CInt64_GreaterEqualU(val1, val2));
|
|
else
|
|
CInt64_SetULong(&val, CInt64_GreaterEqual(val1, val2));
|
|
flag = 1;
|
|
break;
|
|
case EEQU:
|
|
CInt64_SetULong(&val, CInt64_Equal(val1, val2));
|
|
flag = 1;
|
|
break;
|
|
case ENOTEQU:
|
|
CInt64_SetULong(&val, CInt64_NotEqual(val1, val2));
|
|
flag = 1;
|
|
break;
|
|
}
|
|
|
|
if (flag) {
|
|
IRO_TruncateValueToType(&val, nd->rtype);
|
|
expr = IRO_NewENode(EINTCONST);
|
|
expr->rtype = nd->rtype;
|
|
expr->data.intval = val;
|
|
nd->u.diadic.left->type = IROLinearNop;
|
|
nd->u.diadic.right->type = IROLinearNop;
|
|
nd->type = IROLinearOperand;
|
|
nd->u.node = expr;
|
|
}
|
|
}
|
|
|
|
if (IRO_IsFloatConstant(nd->u.diadic.left) && IRO_IsFloatConstant(nd->u.diadic.right)) {
|
|
Float fval1 = nd->u.diadic.left->u.node->data.floatval;
|
|
Float fval2 = nd->u.diadic.right->u.node->data.floatval;
|
|
Float fval;
|
|
flag = 0;
|
|
isCompare = 0;
|
|
switch (nd->nodetype) {
|
|
case EADD:
|
|
fval = CMach_CalcFloatDiadic(nd->rtype, fval1, '+', fval2);
|
|
flag = 1;
|
|
break;
|
|
case ESUB:
|
|
fval = CMach_CalcFloatDiadic(nd->rtype, fval1, '-', fval2);
|
|
flag = 1;
|
|
break;
|
|
case EMUL:
|
|
fval = CMach_CalcFloatDiadic(nd->rtype, fval1, '*', fval2);
|
|
flag = 1;
|
|
break;
|
|
case EDIV:
|
|
fval = CMach_CalcFloatDiadic(nd->rtype, fval1, '/', fval2);
|
|
flag = 1;
|
|
break;
|
|
case ELESS:
|
|
CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, '<', fval2));
|
|
flag = 1;
|
|
isCompare = 1;
|
|
break;
|
|
case EGREATER:
|
|
CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, '>', fval2));
|
|
flag = 1;
|
|
isCompare = 1;
|
|
break;
|
|
case ELESSEQU:
|
|
CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, TK_LESS_EQUAL, fval2));
|
|
flag = 1;
|
|
isCompare = 1;
|
|
break;
|
|
case EGREATEREQU:
|
|
CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, TK_GREATER_EQUAL, fval2));
|
|
flag = 1;
|
|
isCompare = 1;
|
|
break;
|
|
case EEQU:
|
|
CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, TK_LOGICAL_EQ, fval2));
|
|
flag = 1;
|
|
isCompare = 1;
|
|
break;
|
|
case ENOTEQU:
|
|
CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, TK_LOGICAL_NE, fval2));
|
|
flag = 1;
|
|
isCompare = 1;
|
|
break;
|
|
}
|
|
|
|
if (flag) {
|
|
if (isCompare) {
|
|
IRO_TruncateValueToType(&val, nd->rtype);
|
|
expr = IRO_NewENode(EINTCONST);
|
|
expr->rtype = nd->rtype;
|
|
expr->data.intval = val;
|
|
nd->u.diadic.left->type = IROLinearNop;
|
|
nd->u.diadic.right->type = IROLinearNop;
|
|
nd->type = IROLinearOperand;
|
|
nd->u.node = expr;
|
|
} else {
|
|
expr = IRO_NewENode(EFLOATCONST);
|
|
expr->rtype = nd->rtype;
|
|
expr->data.floatval = fval;
|
|
nd->u.diadic.left->type = IROLinearNop;
|
|
nd->u.diadic.right->type = IROLinearNop;
|
|
nd->type = IROLinearOperand;
|
|
nd->u.node = expr;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
IRO_CheckForUserBreak();
|
|
}
|
|
|
|
Boolean IRO_EvaluateConditionals(void) {
|
|
IRONode *fnode;
|
|
IROLinear *nd;
|
|
Boolean changed = 0;
|
|
SwitchInfo *switchInfo;
|
|
SwitchCase *swcase;
|
|
char found;
|
|
CInt64 val;
|
|
|
|
for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
|
|
nd = fnode->last;
|
|
switch (nd->type) {
|
|
case IROLinearIf:
|
|
case IROLinearIfNot:
|
|
if (IRO_IsIntConstant(nd->u.label.x4)) {
|
|
Boolean isZero = CInt64_IsZero(&nd->u.label.x4->u.node->data.intval);
|
|
IRO_NopOut(nd->u.label.x4);
|
|
if ((isZero == 0) == (nd->type == IROLinearIf))
|
|
nd->type = IROLinearGoto;
|
|
else
|
|
nd->type = IROLinearNop;
|
|
changed = 1;
|
|
}
|
|
break;
|
|
|
|
case IROLinearSwitch:
|
|
if (IRO_IsIntConstant(nd->u.swtch.x4)) {
|
|
val = nd->u.swtch.x4->u.node->data.intval;
|
|
switchInfo = nd->u.swtch.info;
|
|
swcase = switchInfo->cases;
|
|
|
|
IRO_NopOut(nd->u.swtch.x4);
|
|
nd->type = IROLinearGoto;
|
|
|
|
found = 0;
|
|
while (swcase) {
|
|
if (CInt64_GreaterEqual(val, swcase->min) && CInt64_LessEqual(val, swcase->max)) {
|
|
found = 1;
|
|
nd->u.label.label = swcase->label;
|
|
break;
|
|
}
|
|
swcase = swcase->next;
|
|
}
|
|
|
|
if (!found)
|
|
nd->u.label.label = switchInfo->defaultlabel;
|
|
changed = 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (changed) {
|
|
IRO_ComputeSuccPred();
|
|
IRO_ComputeDom();
|
|
}
|
|
IRO_CheckForUserBreak();
|
|
|
|
return changed;
|
|
}
|
|
|
|
static int EEquConst(IROLinear *nd) {
|
|
return nd && (nd->nodetype == EEQU) && IRO_IsIntConstant(nd->u.diadic.right);
|
|
}
|
|
|
|
static Object *VEquConst(IROLinear *nd) {
|
|
if (EEquConst(nd))
|
|
return IRO_IsVariable(nd->u.diadic.left);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static int IsConsecutive(CInt64 a, CInt64 b) {
|
|
CInt64 diff;
|
|
|
|
if (!CInt64_Equal(a, cint64_min) && !CInt64_Equal(b, cint64_min)) {
|
|
diff = CInt64_Sub(b, a);
|
|
return CInt64_Equal(diff, cint64_one) || CInt64_Equal(diff, cint64_negone);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static IROLinear *findLabel(CLabel *label) {
|
|
IROLinear *nd;
|
|
|
|
for (nd = IRO_FirstLinear; nd; nd = nd->next) {
|
|
if (nd->type == IROLinearLabel && nd->u.label.label == label)
|
|
break;
|
|
}
|
|
|
|
return nd;
|
|
}
|
|
|
|
static IROLinear *leftLeaveOf(IROLinear *nd) {
|
|
switch (nd->type) {
|
|
case IROLinearOp1Arg:
|
|
return leftLeaveOf(nd->u.monadic);
|
|
case IROLinearOp2Arg:
|
|
return leftLeaveOf(nd->u.diadic.left);
|
|
case IROLinearOperand:
|
|
return nd;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static int checkNode(IRONode *fnode) {
|
|
IROLinear *nd;
|
|
|
|
if (fnode->numpred <= 1) {
|
|
nd = fnode->first;
|
|
while (nd != fnode->last && (nd->type == IROLinearNop || nd->type == IROLinearLabel))
|
|
nd = nd->next;
|
|
|
|
if (nd == leftLeaveOf(fnode->last->u.label.x4))
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int checkLabel(CLabel *label, IRONode *fnode) {
|
|
switch (fnode->last->type) {
|
|
case IROLinearIf:
|
|
if (label == fnode->last->u.label.label)
|
|
return 1;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Object *checkExpr(Object *a, IROLinear *nd) {
|
|
Object *b = VEquConst(nd);
|
|
|
|
if ((!a || a == b) && !IRO_HasSideEffect(nd))
|
|
return b;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int checkStruct(IRONode *fnode1, IRONode *fnode2) {
|
|
CLabel *label;
|
|
Object *var;
|
|
|
|
if (fnode1 == fnode2)
|
|
return (int) checkExpr(NULL, fnode1->last->u.label.x4);
|
|
|
|
label = fnode1->last->u.label.label;
|
|
var = IRO_IsVariable(fnode1->last->u.label.x4->u.monadic);
|
|
return checkNode(fnode2) && checkLabel(label, fnode2) && checkExpr(var, fnode2->last->u.label.x4);
|
|
}
|
|
|
|
typedef struct ReduceInfo {
|
|
int x0;
|
|
int x4;
|
|
Object *x8;
|
|
IRONode *fnode;
|
|
struct ReduceInfo *next;
|
|
CInt64 val;
|
|
} ReduceInfo;
|
|
|
|
static int MarkPattern1(ReduceInfo *info1, ReduceInfo *info2, CInt64 *val) {
|
|
ReduceInfo *scan;
|
|
|
|
if (!info2)
|
|
return 0;
|
|
|
|
if (info2->x0)
|
|
return MarkPattern1(info1, info2->next, val);
|
|
|
|
for (scan = info1; scan; scan = scan->next) {
|
|
if (scan->x0 == 2) {
|
|
if (CInt64_Equal(info2->val, scan->val)) {
|
|
IRO_NopOut(scan->fnode->last);
|
|
IRO_NopOut(scan->fnode->last->u.label.x4); // right union?
|
|
scan->x0 = -1;
|
|
return MarkPattern1(info1, info2->next, val);
|
|
}
|
|
|
|
if (IsConsecutive(info2->val, scan->val)) {
|
|
info2->x0 = 2;
|
|
if (CInt64_Greater(*val, scan->val))
|
|
*val = scan->val;
|
|
if (CInt64_Greater(*val, info2->val))
|
|
*val = info2->val;
|
|
MarkPattern1(scan->next, info2, val);
|
|
MarkPattern1(info1, info1->next, val);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return MarkPattern1(info1, info2->next, val);
|
|
}
|
|
|
|
static int DoReducible1(ReduceInfo *info, CInt64 val) {
|
|
ReduceInfo *last;
|
|
ReduceInfo *scan;
|
|
IROLinear *right;
|
|
IROLinear *left;
|
|
IROLinear *typconRight;
|
|
IROLinear *typconLeft;
|
|
IROLinear *cond;
|
|
int count;
|
|
|
|
count = 0;
|
|
for (scan = info; scan; scan = scan->next) {
|
|
if (scan->x0 == 2) {
|
|
last = scan;
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (!count)
|
|
return 0;
|
|
|
|
for (scan = info; scan != last; scan = scan->next) {
|
|
if (scan->x0 == 2) {
|
|
scan->x0 = -1;
|
|
IRO_NopOut(scan->fnode->last);
|
|
IRO_NopOut(scan->fnode->last->u.label.x4);
|
|
}
|
|
}
|
|
|
|
last->x0 = -1;
|
|
|
|
cond = last->fnode->last;
|
|
cond->u.label.x4->nodetype = ELESSEQU;
|
|
CInt64_SetULong(&cond->u.label.x4->u.diadic.right->u.node->data.intval, count - 1);
|
|
|
|
typconLeft = IRO_NewLinear(IROLinearOp1Arg);
|
|
typconLeft->nodetype = ETYPCON;
|
|
typconLeft->rtype = IRO_UnsignedType(cond->u.label.x4->u.diadic.left->rtype);
|
|
typconLeft->index = ++IRO_NumLinear;
|
|
|
|
typconRight = IRO_NewLinear(IROLinearOp1Arg);
|
|
*typconRight = *typconLeft;
|
|
typconRight->index = ++IRO_NumLinear;
|
|
|
|
left = IRO_NewLinear(IROLinearOp2Arg);
|
|
left->nodetype = EADD;
|
|
left->rtype = cond->u.label.x4->u.diadic.left->rtype;
|
|
left->index = ++IRO_NumLinear;
|
|
|
|
right = IRO_NewLinear(IROLinearOperand);
|
|
right->nodetype = EINTCONST;
|
|
right->rtype = cond->u.label.x4->u.diadic.left->rtype;
|
|
right->index = ++IRO_NumLinear;
|
|
right->u.node = IRO_NewENode(EINTCONST);
|
|
right->u.node->data.intval = CInt64_Neg(val);
|
|
right->u.node->rtype = right->rtype;
|
|
|
|
typconLeft->next = cond->u.label.x4->u.diadic.left->next;
|
|
cond->u.label.x4->u.diadic.left->next = right;
|
|
right->next = left;
|
|
left->next = typconLeft;
|
|
|
|
typconRight->next = cond->u.label.x4->u.diadic.right->next;
|
|
cond->u.label.x4->u.diadic.right->next = typconRight;
|
|
|
|
typconLeft->u.monadic = left;
|
|
left->u.diadic.left = cond->u.label.x4->u.diadic.left;
|
|
left->u.diadic.right = right;
|
|
cond->u.label.x4->u.diadic.left = typconLeft;
|
|
typconRight->u.monadic = cond->u.label.x4->u.diadic.right;
|
|
cond->u.label.x4->u.diadic.right = typconRight;
|
|
|
|
return count;
|
|
};
|
|
|
|
static int ReducePattern1(IRONode *startnode, IRONode *endnode) {
|
|
ReduceInfo *infos;
|
|
ReduceInfo *info;
|
|
int changed = 0;
|
|
int count;
|
|
IRONode *fnode;
|
|
int i;
|
|
int j;
|
|
CInt64 val;
|
|
|
|
if (startnode == endnode)
|
|
return 0;
|
|
|
|
count = 0;
|
|
for (fnode = startnode; fnode != endnode; fnode = fnode->nextnode)
|
|
count++;
|
|
|
|
infos = oalloc(sizeof(ReduceInfo) * ++count);
|
|
|
|
fnode = startnode;
|
|
for (i = 0; i < count; i++) {
|
|
infos[i].x0 = 0;
|
|
infos[i].x4 = 0;
|
|
infos[i].fnode = fnode;
|
|
infos[i].next = NULL;
|
|
infos[i].x8 = VEquConst(fnode->last->u.label.x4);
|
|
if (infos[i].x8) {
|
|
infos[i].val = fnode->last->u.label.x4->u.diadic.right->u.node->data.intval;
|
|
infos[i].x4 = 1;
|
|
}
|
|
fnode = fnode->nextnode;
|
|
}
|
|
|
|
for (j = 0; j < count; j++) {
|
|
if (infos[j].x4 == 1 && infos[j].x8) {
|
|
infos[j].x4 = -1;
|
|
info = &infos[j];
|
|
for (i = j + 1; i < count; i++) {
|
|
if (infos[j].x8 == infos[i].x8) {
|
|
info->next = &infos[i];
|
|
info = &infos[i];
|
|
infos[i].x4 = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < count; j++) {
|
|
if (infos[j].x4 == -1) {
|
|
for (info = &infos[j]; info; info = info->next) {
|
|
if (info->x0 == 0) {
|
|
info->x0 = 2;
|
|
val = info->val;
|
|
if (MarkPattern1(&infos[j], info->next, &val)) {
|
|
changed = 1;
|
|
DoReducible1(&infos[j], val);
|
|
} else {
|
|
info->x0 = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
static int ReduceConsecutiveIf(IRONode *startnode, IRONode *endnode) {
|
|
IRONode *node31;
|
|
IRONode *node30;
|
|
int changed = 0;
|
|
|
|
while (startnode != endnode) {
|
|
if (checkStruct(startnode, startnode))
|
|
break;
|
|
startnode = startnode->nextnode;
|
|
}
|
|
|
|
node31 = startnode;
|
|
if (startnode != endnode) {
|
|
node30 = startnode;
|
|
node31 = startnode->nextnode;
|
|
while (node31 != endnode) {
|
|
if (checkStruct(startnode, node31)) {
|
|
node30 = node31;
|
|
node31 = node31->nextnode;
|
|
} else {
|
|
node31 = node30;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (node31 == endnode && !checkStruct(startnode, node31))
|
|
node31 = node30;
|
|
|
|
if (startnode != node31 && ReducePattern1(startnode, node31))
|
|
changed = 1;
|
|
|
|
if (node31 != endnode)
|
|
node31 = node31->nextnode;
|
|
}
|
|
|
|
if (node31 != endnode && ReduceConsecutiveIf(node31, endnode))
|
|
changed = 1;
|
|
|
|
return changed;
|
|
}
|
|
|
|
int IRO_SimplifyConditionals(void) {
|
|
IRONode *fnode;
|
|
IRONode *start;
|
|
IRONode *end;
|
|
int changed = 0;
|
|
|
|
for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
|
|
if (fnode->last->type == IROLinearIf) {
|
|
start = end = fnode;
|
|
while (fnode->nextnode && fnode->nextnode->last->type == IROLinearIf) {
|
|
end = fnode = fnode->nextnode;
|
|
}
|
|
if (start != end && ReduceConsecutiveIf(start, end))
|
|
changed = 1;
|
|
}
|
|
}
|
|
|
|
if (changed) {
|
|
IRO_ComputeSuccPred();
|
|
IRO_ComputeDom();
|
|
}
|
|
IRO_CheckForUserBreak();
|
|
return changed;
|
|
}
|
|
|
|
Boolean IRO_EvaluateDefinitePointers(Object *func) {
|
|
IROLinear *nd;
|
|
Boolean result; // r29
|
|
Boolean changed; // r28
|
|
Boolean changed2; // r26
|
|
IROLinear *nd2; // r25
|
|
IROListNode *scan; // r25
|
|
IROListNode *list;
|
|
|
|
if (!copts.opt_pointer_analysis)
|
|
return 0;
|
|
|
|
result = 0;
|
|
|
|
do {
|
|
changed = 0;
|
|
|
|
for (nd = IRO_FirstLinear; nd; nd = nd->next) {
|
|
if (
|
|
nd->type == IROLinearOp1Arg &&
|
|
nd->nodetype == EINDIRECT &&
|
|
!(nd->flags & IROLF_Assigned) &&
|
|
nd->pointsToFunction &&
|
|
!IRO_HasSideEffect(nd) &&
|
|
PointerAnalysis_IsLinearNodePointerExprDefinite(func, nd)
|
|
)
|
|
{
|
|
list = NULL;
|
|
PointerAnalysis_LookupLinearNodePointerExpr(func, nd, &list);
|
|
if (list) {
|
|
if (list->list.head && list->list.tail && !list->nextList) {
|
|
changed2 = IRO_LocateFather_Cut_And_Paste(nd, list->list.tail) != NULL;
|
|
if (changed2) {
|
|
IRO_PasteAfter(list->list.head, list->list.tail, nd);
|
|
for (nd2 = list->list.head; nd2 != list->list.tail->next; nd2 = nd2->next) {
|
|
if (nd2->type == IROLinearOperand && nd2->u.node->type == EOBJREF) {
|
|
if (nd2->u.node->data.objref->datatype == DDATA || nd2->u.node->data.objref->datatype == DLOCAL)
|
|
IRO_FindVar(nd2->u.node->data.objref, 1, 1);
|
|
else
|
|
nd2->u.node->data.objref->varptr = NULL;
|
|
}
|
|
}
|
|
}
|
|
changed |= changed2;
|
|
}
|
|
|
|
while (list) {
|
|
scan = list->nextList;
|
|
IRO_free(list);
|
|
list = scan;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
result |= changed;
|
|
IRO_CheckForUserBreak();
|
|
} while (changed);
|
|
|
|
return result;
|
|
}
|