MWCC/compiler_and_linker/unsorted/IroTransform.c

2795 lines
100 KiB
C

#include "compiler/IroTransform.h"
#include "compiler/CError.h"
#include "compiler/CFunc.h"
#include "compiler/CInt64.h"
#include "compiler/CIRTransform.h"
#include "compiler/CMachine.h"
#include "compiler/CPrep.h"
#include "compiler/CompilerTools.h"
#include "compiler/IroDump.h"
#include "compiler/IroLinearForm.h"
#include "compiler/IroMalloc.h"
#include "compiler/IroPointerAnalysis.h"
#include "compiler/IROUseDef.h"
#include "compiler/IroUtil.h"
#include "compiler/IroVars.h"
#include "compiler/enode.h"
#include "compiler/types.h"
ENodeType ExprType;
ENode *IndirectRef;
Boolean FirstTime;
CInt64 OperandConst;
Object *OperandObject;
ENodeList *FirstAddend;
ENodeList *LastAddend;
static ENodeType AssignmentOp[MAXEXPR];
static ENodeType ComplementaryOpLogical[MAXEXPR];
static ENodeType ComplementaryOp[MAXEXPR];
// forward decls
static void DoDiadic(IROLinear *nd);
static int GetTypeSize(Type *type) {
if (type->size == 1)
return 0;
if (type->size == 2)
return 1;
if (type->size == 4)
return 2;
if (type->size == 8)
return 3;
return -1;
}
void IRO_InitializeAssignmentOpArray(void) {
int i;
for (i = 0; i < MAXEXPR; i++)
AssignmentOp[i] = MAXEXPR;
AssignmentOp[EPOSTINC] = MAXEXPR;
AssignmentOp[EPOSTDEC] = MAXEXPR;
AssignmentOp[EPREINC] = MAXEXPR;
AssignmentOp[EPREDEC] = MAXEXPR;
AssignmentOp[EINDIRECT] = MAXEXPR;
AssignmentOp[EMONMIN] = MAXEXPR;
AssignmentOp[EBINNOT] = MAXEXPR;
AssignmentOp[ELOGNOT] = MAXEXPR;
AssignmentOp[EFORCELOAD] = MAXEXPR;
AssignmentOp[EMUL] = EMULASS;
AssignmentOp[EMULV] = MAXEXPR;
AssignmentOp[EDIV] = EDIVASS;
AssignmentOp[EMODULO] = EMODASS;
AssignmentOp[EADDV] = MAXEXPR;
AssignmentOp[ESUBV] = MAXEXPR;
AssignmentOp[EADD] = EADDASS;
AssignmentOp[ESUB] = ESUBASS;
AssignmentOp[ESHL] = ESHLASS;
AssignmentOp[ESHR] = ESHRASS;
AssignmentOp[ELESS] = MAXEXPR;
AssignmentOp[EGREATER] = MAXEXPR;
AssignmentOp[ELESSEQU] = MAXEXPR;
AssignmentOp[EGREATEREQU] = MAXEXPR;
AssignmentOp[EEQU] = MAXEXPR;
AssignmentOp[ENOTEQU] = MAXEXPR;
AssignmentOp[EAND] = EANDASS;
AssignmentOp[EXOR] = EXORASS;
AssignmentOp[EOR] = EORASS;
AssignmentOp[ELAND] = MAXEXPR;
AssignmentOp[ELOR] = MAXEXPR;
AssignmentOp[EASS] = MAXEXPR;
AssignmentOp[EMULASS] = MAXEXPR;
AssignmentOp[EDIVASS] = MAXEXPR;
AssignmentOp[EMODASS] = MAXEXPR;
AssignmentOp[EADDASS] = MAXEXPR;
AssignmentOp[ESUBASS] = MAXEXPR;
AssignmentOp[ESHLASS] = MAXEXPR;
AssignmentOp[ESHRASS] = MAXEXPR;
AssignmentOp[EANDASS] = MAXEXPR;
AssignmentOp[EXORASS] = MAXEXPR;
AssignmentOp[EORASS] = MAXEXPR;
AssignmentOp[ECOMMA] = MAXEXPR;
AssignmentOp[EPMODULO] = MAXEXPR;
AssignmentOp[EROTL] = MAXEXPR;
AssignmentOp[EROTR] = MAXEXPR;
AssignmentOp[EBCLR] = MAXEXPR;
AssignmentOp[EBTST] = MAXEXPR;
AssignmentOp[EBSET] = MAXEXPR;
AssignmentOp[ETYPCON] = MAXEXPR;
AssignmentOp[EBITFIELD] = MAXEXPR;
AssignmentOp[EINTCONST] = MAXEXPR;
AssignmentOp[EFLOATCONST] = MAXEXPR;
AssignmentOp[ESTRINGCONST] = MAXEXPR;
AssignmentOp[ECOND] = MAXEXPR;
AssignmentOp[EFUNCCALL] = MAXEXPR;
AssignmentOp[EFUNCCALLP] = MAXEXPR;
AssignmentOp[EOBJREF] = MAXEXPR;
AssignmentOp[EMFPOINTER] = MAXEXPR;
AssignmentOp[ENULLCHECK] = MAXEXPR;
AssignmentOp[EPRECOMP] = MAXEXPR;
AssignmentOp[ETEMP] = MAXEXPR;
AssignmentOp[EARGOBJ] = MAXEXPR;
AssignmentOp[ELOCOBJ] = MAXEXPR;
AssignmentOp[ELABEL] = MAXEXPR;
AssignmentOp[ESETCONST] = MAXEXPR;
AssignmentOp[ENEWEXCEPTION] = MAXEXPR;
AssignmentOp[ENEWEXCEPTIONARRAY] = MAXEXPR;
AssignmentOp[EOBJLIST] = MAXEXPR;
AssignmentOp[EMEMBER] = MAXEXPR;
AssignmentOp[ETEMPLDEP] = MAXEXPR;
AssignmentOp[EINSTRUCTION] = MAXEXPR;
AssignmentOp[EDEFINE] = MAXEXPR;
AssignmentOp[EREUSE] = MAXEXPR;
AssignmentOp[EASSBLK] = MAXEXPR;
AssignmentOp[EVECTOR128CONST] = MAXEXPR;
AssignmentOp[ECONDASS] = MAXEXPR;
}
void IRO_InitializeComplementaryOpArray(void) {
int i;
for (i = 0; i < MAXEXPR; i++)
ComplementaryOp[i] = MAXEXPR;
ComplementaryOp[EPOSTINC] = EPOSTDEC;
ComplementaryOp[EPOSTDEC] = EPOSTINC;
ComplementaryOp[EPREINC] = EPREDEC;
ComplementaryOp[EPREDEC] = EPREINC;
ComplementaryOp[EINDIRECT] = MAXEXPR;
ComplementaryOp[EMONMIN] = EMONMIN;
ComplementaryOp[EBINNOT] = EBINNOT;
ComplementaryOp[ELOGNOT] = ELOGNOT;
ComplementaryOp[EFORCELOAD] = MAXEXPR;
ComplementaryOp[EMUL] = EDIV;
ComplementaryOp[EMULV] = MAXEXPR;
ComplementaryOp[EDIV] = EMUL;
ComplementaryOp[EMODULO] = MAXEXPR;
ComplementaryOp[EADDV] = ESUBV;
ComplementaryOp[ESUBV] = EADDV;
ComplementaryOp[EADD] = ESUB;
ComplementaryOp[ESUB] = EADD;
ComplementaryOp[ESHL] = ESHR;
ComplementaryOp[ESHR] = ESHL;
ComplementaryOp[ELESS] = EGREATER;
ComplementaryOp[EGREATER] = ELESS;
ComplementaryOp[ELESSEQU] = EGREATEREQU;
ComplementaryOp[EGREATEREQU] = ELESSEQU;
ComplementaryOp[EEQU] = ENOTEQU;
ComplementaryOp[ENOTEQU] = EEQU;
ComplementaryOp[EAND] = EOR;
ComplementaryOp[EXOR] = MAXEXPR;
ComplementaryOp[EOR] = EAND;
ComplementaryOp[ELAND] = ELOR;
ComplementaryOp[ELOR] = ELAND;
ComplementaryOp[EASS] = MAXEXPR;
ComplementaryOp[EMULASS] = EDIVASS;
ComplementaryOp[EDIVASS] = EMULASS;
ComplementaryOp[EMODASS] = MAXEXPR;
ComplementaryOp[EADDASS] = ESUBASS;
ComplementaryOp[ESUBASS] = EADDASS;
ComplementaryOp[ESHLASS] = ESHRASS;
ComplementaryOp[ESHRASS] = ESHLASS;
ComplementaryOp[EANDASS] = EORASS;
ComplementaryOp[EXORASS] = MAXEXPR;
ComplementaryOp[EORASS] = EANDASS;
ComplementaryOp[ECOMMA] = MAXEXPR;
ComplementaryOp[EPMODULO] = MAXEXPR;
ComplementaryOp[EROTL] = EROTR;
ComplementaryOp[EROTR] = EROTL;
ComplementaryOp[EBCLR] = MAXEXPR;
ComplementaryOp[EBTST] = MAXEXPR;
ComplementaryOp[EBSET] = MAXEXPR;
ComplementaryOp[ETYPCON] = MAXEXPR;
ComplementaryOp[EBITFIELD] = MAXEXPR;
ComplementaryOp[EINTCONST] = MAXEXPR;
ComplementaryOp[EFLOATCONST] = MAXEXPR;
ComplementaryOp[ESTRINGCONST] = MAXEXPR;
ComplementaryOp[ECOND] = MAXEXPR;
ComplementaryOp[EFUNCCALL] = MAXEXPR;
ComplementaryOp[EFUNCCALLP] = MAXEXPR;
ComplementaryOp[EOBJREF] = MAXEXPR;
ComplementaryOp[EMFPOINTER] = MAXEXPR;
ComplementaryOp[ENULLCHECK] = MAXEXPR;
ComplementaryOp[EPRECOMP] = MAXEXPR;
ComplementaryOp[ETEMP] = MAXEXPR;
ComplementaryOp[EARGOBJ] = MAXEXPR;
ComplementaryOp[ELOCOBJ] = MAXEXPR;
ComplementaryOp[ELABEL] = MAXEXPR;
ComplementaryOp[ESETCONST] = MAXEXPR;
ComplementaryOp[ENEWEXCEPTION] = MAXEXPR;
ComplementaryOp[ENEWEXCEPTIONARRAY] = MAXEXPR;
ComplementaryOp[EOBJLIST] = MAXEXPR;
ComplementaryOp[EMEMBER] = MAXEXPR;
ComplementaryOp[ETEMPLDEP] = MAXEXPR;
ComplementaryOp[EINSTRUCTION] = MAXEXPR;
ComplementaryOp[EDEFINE] = MAXEXPR;
ComplementaryOp[EREUSE] = MAXEXPR;
ComplementaryOp[EASSBLK] = MAXEXPR;
ComplementaryOp[EVECTOR128CONST] = MAXEXPR;
ComplementaryOp[ECONDASS] = MAXEXPR;
}
void IRO_InitializeComplementaryOpLogicalArray(void) {
int i;
for (i = 0; i < MAXEXPR; i++)
ComplementaryOpLogical[i] = MAXEXPR;
ComplementaryOpLogical[EPOSTINC] = MAXEXPR;
ComplementaryOpLogical[EPOSTDEC] = MAXEXPR;
ComplementaryOpLogical[EPREINC] = MAXEXPR;
ComplementaryOpLogical[EPREDEC] = MAXEXPR;
ComplementaryOpLogical[EINDIRECT] = MAXEXPR;
ComplementaryOpLogical[EMONMIN] = MAXEXPR;
ComplementaryOpLogical[EBINNOT] = MAXEXPR;
ComplementaryOpLogical[ELOGNOT] = ELOGNOT;
ComplementaryOpLogical[EFORCELOAD] = MAXEXPR;
ComplementaryOpLogical[EMUL] = MAXEXPR;
ComplementaryOpLogical[EMULV] = MAXEXPR;
ComplementaryOpLogical[EDIV] = MAXEXPR;
ComplementaryOpLogical[EMODULO] = MAXEXPR;
ComplementaryOpLogical[EADDV] = MAXEXPR;
ComplementaryOpLogical[ESUBV] = MAXEXPR;
ComplementaryOpLogical[EADD] = MAXEXPR;
ComplementaryOpLogical[ESUB] = MAXEXPR;
ComplementaryOpLogical[ESHL] = MAXEXPR;
ComplementaryOpLogical[ESHR] = MAXEXPR;
ComplementaryOpLogical[ELESS] = EGREATEREQU;
ComplementaryOpLogical[EGREATER] = ELESSEQU;
ComplementaryOpLogical[ELESSEQU] = EGREATER;
ComplementaryOpLogical[EGREATEREQU] = ELESS;
ComplementaryOpLogical[EEQU] = ENOTEQU;
ComplementaryOpLogical[ENOTEQU] = EEQU;
ComplementaryOpLogical[EAND] = MAXEXPR;
ComplementaryOpLogical[EXOR] = MAXEXPR;
ComplementaryOpLogical[EOR] = MAXEXPR;
ComplementaryOpLogical[ELAND] = ELOR;
ComplementaryOpLogical[ELOR] = ELAND;
ComplementaryOpLogical[EASS] = MAXEXPR;
ComplementaryOpLogical[EMULASS] = MAXEXPR;
ComplementaryOpLogical[EDIVASS] = MAXEXPR;
ComplementaryOpLogical[EMODASS] = MAXEXPR;
ComplementaryOpLogical[EADDASS] = MAXEXPR;
ComplementaryOpLogical[ESUBASS] = MAXEXPR;
ComplementaryOpLogical[ESHLASS] = MAXEXPR;
ComplementaryOpLogical[ESHRASS] = MAXEXPR;
ComplementaryOpLogical[EANDASS] = MAXEXPR;
ComplementaryOpLogical[EXORASS] = MAXEXPR;
ComplementaryOpLogical[EORASS] = MAXEXPR;
ComplementaryOpLogical[ECOMMA] = MAXEXPR;
ComplementaryOpLogical[EPMODULO] = MAXEXPR;
ComplementaryOpLogical[EROTL] = MAXEXPR;
ComplementaryOpLogical[EROTR] = MAXEXPR;
ComplementaryOpLogical[EBCLR] = MAXEXPR;
ComplementaryOpLogical[EBTST] = MAXEXPR;
ComplementaryOpLogical[EBSET] = MAXEXPR;
ComplementaryOpLogical[ETYPCON] = MAXEXPR;
ComplementaryOpLogical[EBITFIELD] = MAXEXPR;
ComplementaryOpLogical[EINTCONST] = MAXEXPR;
ComplementaryOpLogical[EFLOATCONST] = MAXEXPR;
ComplementaryOpLogical[ESTRINGCONST] = MAXEXPR;
ComplementaryOpLogical[ECOND] = MAXEXPR;
ComplementaryOpLogical[EFUNCCALL] = MAXEXPR;
ComplementaryOpLogical[EFUNCCALLP] = MAXEXPR;
ComplementaryOpLogical[EOBJREF] = MAXEXPR;
ComplementaryOpLogical[EMFPOINTER] = MAXEXPR;
ComplementaryOpLogical[ENULLCHECK] = MAXEXPR;
ComplementaryOpLogical[EPRECOMP] = MAXEXPR;
ComplementaryOpLogical[ETEMP] = MAXEXPR;
ComplementaryOpLogical[EARGOBJ] = MAXEXPR;
ComplementaryOpLogical[ELOCOBJ] = MAXEXPR;
ComplementaryOpLogical[ELABEL] = MAXEXPR;
ComplementaryOpLogical[ESETCONST] = MAXEXPR;
ComplementaryOpLogical[ENEWEXCEPTION] = MAXEXPR;
ComplementaryOpLogical[ENEWEXCEPTIONARRAY] = MAXEXPR;
ComplementaryOpLogical[EOBJLIST] = MAXEXPR;
ComplementaryOpLogical[EMEMBER] = MAXEXPR;
ComplementaryOpLogical[ETEMPLDEP] = MAXEXPR;
ComplementaryOpLogical[EINSTRUCTION] = MAXEXPR;
ComplementaryOpLogical[EDEFINE] = MAXEXPR;
ComplementaryOpLogical[EREUSE] = MAXEXPR;
ComplementaryOpLogical[EASSBLK] = MAXEXPR;
ComplementaryOpLogical[EVECTOR128CONST] = MAXEXPR;
ComplementaryOpLogical[ECONDASS] = MAXEXPR;
}
static void DoTransformations(IROLinear *nd) {
IROLinear *nd2;
IROLinear *nd3;
IROLinear *nd4;
IROLinear *nd5;
Type *newtype;
SInt32 value;
if (nd->type == IROLinearOp2Arg) {
switch (nd->nodetype) {
case EASS:
nd2 = nd->u.diadic.right;
if (
nd2->type == IROLinearOp2Arg &&
AssignmentOp[nd2->nodetype] < MAXEXPR &&
IRO_TypesEqual(nd->rtype, nd2->rtype) &&
IRO_IsVariable(nd3 = nd->u.diadic.left) &&
!(nd3->flags & IROLF_BitfieldIndirect) &&
IRO_ExprsSame(nd3, nd2->u.diadic.left)
)
{
nd->nodetype = AssignmentOp[nd2->nodetype];
nd->u.diadic.right = nd2->u.diadic.right;
IRO_NopOut(nd2->u.diadic.left);
nd2->type = IROLinearNop;
nd3->flags |= IROLF_Used;
nd3->u.diadic.left->flags |= IROLF_Used;
}
break;
case EMUL:
if (
IS_TYPE_INT(nd->rtype) &&
IRO_IsPow2(nd->u.diadic.right, &value)
)
{
nd->nodetype = ESHL;
CInt64_SetLong(&nd->u.diadic.right->u.node->data.intval, value);
}
break;
case EDIV:
if (
IS_TYPE_INT(nd->rtype) &&
IRO_IsPow2(nd->u.diadic.right, &value)
)
{
if (IRO_IsUnsignedType(nd->rtype)) {
nd->nodetype = ESHR;
CInt64_SetLong(&nd->u.diadic.right->u.node->data.intval, value);
} else if (
!IRO_IsUnsignedType(nd->rtype) &&
TYPE_INTEGRAL(nd->rtype)->integral != IT_BOOL &&
nd->u.diadic.left->nodetype == ETYPCON &&
IS_TYPE_INT(nd->u.diadic.left->u.monadic->rtype) &&
IRO_IsUnsignedType(nd->u.diadic.left->u.monadic->rtype) &&
nd->u.diadic.left->u.monadic->rtype->size < nd->u.diadic.left->rtype->size
)
{
nd->nodetype = ESHR;
CInt64_SetLong(&nd->u.diadic.right->u.node->data.intval, value);
if (nd->flags & IROLF_Reffed) {
IROLinear *copy = IRO_NewLinear(IROLinearOp1Arg);
memcpy(copy, nd, sizeof(IROLinear));
copy->type = IROLinearOp1Arg;
copy->nodetype = ETYPCON;
copy->index = IRO_NumLinear++;
copy->rtype = nd->rtype;
IRO_PasteAfter(copy, copy, nd);
IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, copy);
copy->u.monadic = nd;
nd->flags |= IROLF_Reffed;
}
nd->rtype = IRO_UnsignedType(nd->rtype);
newtype = IRO_UnsignedType(nd->u.diadic.right->rtype);
nd->u.diadic.right->u.node->rtype = newtype;
nd->u.diadic.right->rtype = newtype;
nd->u.diadic.left->rtype = IRO_UnsignedType(nd->u.diadic.left->rtype);
}
}
break;
case EMODULO:
if (
IS_TYPE_INT(nd->rtype) &&
IRO_IsUnsignedType(nd->rtype) &&
IRO_IsPow2(nd->u.diadic.right, &value)
)
{
nd->nodetype = EAND;
nd->u.diadic.right->u.node->data.intval = CInt64_Sub(nd->u.diadic.right->u.node->data.intval, cint64_one);
}
break;
case EEQU:
if (
(nd2 = IRO_LocateFather(nd)) &&
nd2->nodetype == ETYPCON &&
IS_TYPE_INT(nd2->rtype) &&
(nd3 = IRO_LocateFather(nd2)) &&
nd3->nodetype == ELOGNOT &&
(nd4 = IRO_LocateFather(nd3)) &&
nd4->nodetype == ETYPCON &&
IS_TYPE_INT(nd4->rtype) &&
(
((nd5 = IRO_LocateFather(nd4)) && nd5->type == IROLinearIf) ||
nd5->type == IROLinearIfNot
)
)
{
IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd4, nd);
nd->nodetype = ENOTEQU;
nd2->type = IROLinearNop;
nd3->type = IROLinearNop;
nd4->type = IROLinearNop;
}
break;
}
}
}
static void IRO_SwitchChildren(IROLinear *nd) {
IROLinear *tmp = nd->u.diadic.left;
nd->u.diadic.left = nd->u.diadic.right;
nd->u.diadic.right = tmp;
}
static void ReplaceExprWithConst(IROLinear *nd, CInt64 val) {
IRO_NopOut(nd);
nd->type = IROLinearOperand;
nd->nodetype = EINTCONST;
nd->u.node = IRO_NewENode(EINTCONST);
nd->u.node->data.intval = val;
nd->u.node->flags = nd->nodeflags;
nd->u.node->rtype = nd->rtype;
if (IS_TYPE_FLOAT(nd->rtype)) {
nd->u.node->type = EFLOATCONST;
nd->nodetype = EFLOATCONST;
nd->u.node->data.floatval = CMach_CalcFloatConvertFromInt(TYPE(&stsignedlong), val);
}
}
static void ReplaceExprWithLeftChild(IROLinear *nd) {
IROLinear *left = nd->u.diadic.left;
IROLinear *right = nd->u.diadic.right;
if (left->rtype == nd->rtype) {
IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, left);
left->flags = nd->flags;
left->nodeflags = nd->nodeflags;
nd->type = IROLinearNop;
IRO_NopOut(right);
} else {
nd->type = IROLinearOp1Arg;
nd->nodetype = ETYPCON;
nd->u.monadic = left;
IRO_NopOut(right);
}
}
static void ReplaceExprWithRightChild(IROLinear *nd) {
IROLinear *left = nd->u.diadic.left;
IROLinear *right = nd->u.diadic.right;
if (right->rtype == nd->rtype) {
IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, right);
right->flags = nd->flags;
right->nodeflags = nd->nodeflags;
nd->type = IROLinearNop;
IRO_NopOut(left);
} else {
nd->type = IROLinearOp1Arg;
nd->nodetype = ETYPCON;
nd->u.monadic = right;
IRO_NopOut(left);
}
}
static void ReplaceExprWithMonaminRight(IROLinear *nd) {
IROLinear *left = nd->u.diadic.left;
IROLinear *right = nd->u.diadic.right;
if (right->rtype == nd->rtype) {
nd->type = IROLinearOp1Arg;
nd->nodetype = EMONMIN;
nd->u.monadic = right;
IRO_NopOut(left);
} else {
IRO_NopOut(left);
left->type = IROLinearOp1Arg;
left->nodetype = ETYPCON;
left->expr = right->expr;
left->rtype = nd->rtype;
left->u.monadic = right;
nd->type = IROLinearOp1Arg;
nd->nodetype = EMONMIN;
nd->u.monadic = left;
}
}
static void ReplaceExprWithMonaminLeft(IROLinear *nd) {
IROLinear *left = nd->u.diadic.left;
IROLinear *right = nd->u.diadic.right;
if (left->rtype == nd->rtype) {
nd->type = IROLinearOp1Arg;
nd->nodetype = EMONMIN;
nd->u.monadic = left;
IRO_NopOut(right);
} else {
IRO_NopOut(right);
right->type = IROLinearOp1Arg;
right->nodetype = ETYPCON;
right->expr = left->expr;
right->rtype = nd->rtype;
right->u.monadic = left;
nd->type = IROLinearOp1Arg;
nd->nodetype = EMONMIN;
nd->u.monadic = right;
}
}
static void switchFatherLeftMonadic(IROLinear *nd) {
IROLinear *inner = nd->u.monadic;
IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, inner);
nd->u.monadic = inner->u.monadic;
inner->u.monadic = nd;
inner->rtype = nd->rtype;
inner->flags = nd->flags;
inner->nodeflags = nd->nodeflags;
IRO_CutAndPasteAfter(inner, inner, nd);
}
static void switchFatherLeft(IROLinear *nd, int isRight) {
IROLinear *a;
IROLinear *b;
a = nd->u.diadic.left;
IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, a);
if (isRight) {
nd->u.diadic.left = a->u.diadic.left;
a->u.diadic.left = nd;
b = a->u.diadic.right;
} else {
nd->u.diadic.left = a->u.diadic.right;
a->u.diadic.right = nd;
b = a->u.diadic.left;
}
a->rtype = nd->rtype;
a->flags = nd->flags;
a->nodeflags = nd->nodeflags;
IRO_CutAndPasteAfter(a, a, nd);
IRO_CutAndPasteAfter(IRO_FindFirst(b), b, nd);
}
static void PickCommonsubAtLeftLeft(IROLinear *nd) {
switchFatherLeft(nd, 0);
ReplaceExprWithRightChild(nd->u.diadic.right);
}
static void PickCommonsubAtRightLeft(IROLinear *nd) {
switchFatherLeft(nd, 1);
ReplaceExprWithRightChild(nd->u.diadic.right);
}
static void PickCommonsubAtLeftRight(IROLinear *nd) {
switchFatherLeft(nd, 0);
ReplaceExprWithLeftChild(nd->u.diadic.right);
}
static void PickCommonsubAtRightRight(IROLinear *nd) {
switchFatherLeft(nd, 1);
ReplaceExprWithLeftChild(nd->u.diadic.right);
}
static void DoTransformations11(IROLinear *nd) {
IROLinear *left;
IROLinear *right;
int changed;
int compare;
Type *type;
SInt32 tmp1;
SInt32 tmp2;
CInt64 val;
if (nd->type == IROLinearOp2Arg) {
left = nd->u.diadic.left;
right = nd->u.diadic.right;
if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype))
return;
changed = 0;
if (!IRO_HasSideEffect(left) && !IRO_HasSideEffect(right)) {
if (IRO_IsIntConstant(right) || IRO_IsFloatConstant(right)) {
if (IRO_IsConstantZero(right)) {
switch (nd->nodetype) {
case EADDV:
case ESUBV:
case EADD:
case ESUB:
case ESHL:
case ESHR:
case EXOR:
case EOR:
case ELOR:
case EADDASS:
case ESUBASS:
case ESHLASS:
case ESHRASS:
case EXORASS:
case EORASS:
ReplaceExprWithLeftChild(nd);
changed = 1;
break;
case EMUL:
case EAND:
case ELAND:
ReplaceExprWithConst(nd, cint64_zero);
changed = 1;
break;
case EMULASS:
case EANDASS:
nd->nodetype = EASS;
nd->u.diadic.right->rtype = nd->rtype;
nd->u.diadic.right->u.node->rtype = nd->rtype;
changed = 1;
break;
case EDIV:
case EMODULO:
case EDIVASS:
case EMODASS:
if (nd->stmt->sourceoffset) {
TStreamElement *token = CPrep_CurStreamElement();
token->tokenoffset = nd->stmt->sourceoffset;
CError_SetErrorToken(token);
}
CError_Warning(CErrorStr139);
break;
}
} else if (nd->nodetype == ELAND) {
ReplaceExprWithLeftChild(nd);
changed = 1;
} else if (nd->nodetype == ELOR) {
ReplaceExprWithConst(nd, cint64_one);
changed = 1;
} else if (nd->nodetype == ESHL || nd->nodetype == ESHR || nd->nodetype == ESHLASS || nd->nodetype == ESHRASS) {
type = nd->rtype;
tmp1 = type->size * 8;
if (left->type == IROLinearOp1Arg && left->nodetype == ETYPCON) {
type = left->u.monadic->rtype;
if (
left->u.monadic->type == IROLinearOp1Arg &&
left->u.monadic->nodetype == EINDIRECT &&
left->u.monadic->u.monadic->type == IROLinearOp1Arg &&
left->u.monadic->u.monadic->nodetype == EBITFIELD &&
IS_TYPE_BITFIELD(left->u.monadic->u.monadic->rtype)
)
tmp2 = TYPE_BITFIELD(left->u.monadic->u.monadic->rtype)->unkB;
else
tmp2 = type->size * 8;
} else {
tmp2 = tmp1;
}
switch (nd->nodetype) {
case ESHL:
case ESHLASS:
CInt64_SetLong(&val, tmp1);
if (IRO_IsUnsignedType(type))
compare = CInt64_GreaterEqualU(right->u.node->data.intval, val);
else
compare = CInt64_GreaterEqual(right->u.node->data.intval, val);
break;
case ESHR:
case ESHRASS:
CInt64_SetLong(&val, tmp2);
compare = IRO_IsUnsignedType(type) && CInt64_GreaterEqualU(right->u.node->data.intval, val);
break;
}
if (compare) {
switch (nd->nodetype) {
case ESHL:
case ESHR:
ReplaceExprWithConst(nd, cint64_zero);
break;
case ESHLASS:
case ESHRASS:
nd->nodetype = EASS;
ReplaceExprWithConst(right, cint64_zero);
break;
}
changed = 1;
}
} else if (IRO_IsConstantOne(right)) {
switch (nd->nodetype) {
case EMUL:
case EMULV:
case EDIV:
case EMULASS:
case EDIVASS:
ReplaceExprWithLeftChild(nd);
changed = 1;
break;
case EMODULO:
ReplaceExprWithConst(nd, cint64_zero);
changed = 1;
break;
case EMODASS:
nd->nodetype = EASS;
ReplaceExprWithConst(right, cint64_zero);
nd->u.diadic.right->rtype = nd->rtype;
nd->u.diadic.right->u.node->rtype = nd->rtype;
changed = 1;
break;
}
} else if (IRO_IsConstantNegativeOne(right)) {
switch (nd->nodetype) {
case EMUL:
case EMULV:
case EDIV:
ReplaceExprWithMonaminLeft(nd);
changed = 1;
break;
case EMODULO:
ReplaceExprWithConst(nd, cint64_zero);
changed = 1;
break;
case EMODASS:
nd->nodetype = EASS;
ReplaceExprWithConst(right, cint64_zero);
nd->u.diadic.right->rtype = nd->rtype;
nd->u.diadic.right->u.node->rtype = nd->rtype;
changed = 1;
break;
}
}
}
if (!changed && (IRO_IsIntConstant(left) || IRO_IsFloatConstant(left))) {
if (IRO_IsConstantZero(left)) {
switch (nd->nodetype) {
case EADDV:
case EADD:
case EXOR:
case EOR:
case ELOR:
ReplaceExprWithRightChild(nd);
break;
case EMUL:
case ESHL:
case ESHR:
case EAND:
case ELAND:
ReplaceExprWithConst(nd, cint64_zero);
break;
case ESUBV:
case ESUB:
ReplaceExprWithMonaminRight(nd);
break;
}
} else if (nd->nodetype == ELAND) {
ReplaceExprWithRightChild(nd);
} else if (nd->nodetype == ELOR) {
ReplaceExprWithConst(nd, cint64_one);
} else if (IRO_IsConstantOne(left)) {
switch (nd->nodetype) {
case EMUL:
case EMULV:
ReplaceExprWithRightChild(nd);
break;
}
} else if (IRO_IsConstantNegativeOne(left)) {
switch (nd->nodetype) {
case EMUL:
case EMULV:
ReplaceExprWithMonaminRight(nd);
break;
}
}
}
}
}
}
static void DoTransformations12(IROLinear *nd) {
IROLinear *left;
IROLinear *right;
if (nd->type == IROLinearOp2Arg) {
left = nd->u.diadic.left;
right = nd->u.diadic.right;
if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype))
return;
if (IRO_ExprsSameSemantically(left, right) && !IRO_HasSideEffect(left)) {
switch (nd->nodetype) {
case ESUBV:
case ESUB:
case ELESS:
case EGREATER:
case ENOTEQU:
case EXOR:
ReplaceExprWithConst(nd, cint64_zero);
break;
case ELESSEQU:
case EGREATEREQU:
case EEQU:
ReplaceExprWithConst(nd, cint64_one);
break;
case EAND:
case EOR:
case ELAND:
case ELOR:
case EASS:
case EANDASS:
case EORASS:
ReplaceExprWithLeftChild(nd);
break;
case ESUBASS:
case EXORASS:
nd->nodetype = EASS;
ReplaceExprWithConst(right, cint64_zero);
break;
}
}
}
}
static void DoTransformations13(IROLinear *nd) {
IROLinear *left;
IROLinear *right;
IROLinear *left2;
IROLinear *right2;
IROListNode *tmp;
IROListNode *leftlist;
IROListNode *rightlist;
if (nd->type == IROLinearOp2Arg) {
left = nd->u.diadic.left;
right = nd->u.diadic.right;
if (
!IRO_HasSideEffect(left) &&
!IRO_HasSideEffect(right) &&
(nd->nodetype == EEQU || nd->nodetype == ENOTEQU) &&
PointerAnalysis_IsLinearNodePointerExprDefinite(FunctionName, left) &&
PointerAnalysis_IsLinearNodePointerExprDefinite(FunctionName, right)
)
{
leftlist = NULL;
PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, left, &leftlist);
if (leftlist) {
if (leftlist->list.head && leftlist->list.tail && !leftlist->nextList) {
rightlist = NULL;
PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, right, &rightlist);
if (rightlist) {
if (rightlist->list.head && rightlist->list.tail && !rightlist->nextList) {
left2 = leftlist->list.tail;
right2 = rightlist->list.tail;
if (IRO_ExprsSameSemantically(left2, right2)) {
ReplaceExprWithConst(nd, (nd->nodetype == EEQU) ? cint64_one : cint64_zero);
} else if (left2->type == right2->type && IRO_TypesEqual(left2->rtype, right2->rtype)) {
ReplaceExprWithConst(nd, (nd->nodetype == EEQU) ? cint64_zero : cint64_one);
}
}
while (rightlist) {
tmp = rightlist->nextList;
IRO_free(rightlist);
rightlist = tmp;
}
}
}
while (leftlist) {
tmp = leftlist->nextList;
IRO_free(leftlist);
leftlist = tmp;
}
}
}
}
}
static void DoTransformations21(IROLinear *nd) {
IROLinear *left;
IROLinear *right;
Boolean changed;
if (nd->type == IROLinearOp2Arg) {
left = nd->u.diadic.left;
right = nd->u.diadic.right;
if (left->type == IROLinearOp1Arg && right->type == IROLinearOp1Arg && left->nodetype == right->nodetype) {
switch (left->nodetype) {
case EMONMIN:
case EBINNOT:
case ELOGNOT:
changed = 0;
switch (nd->nodetype) {
case EXOR:
if (left->nodetype == EBINNOT)
goto collapse;
break;
case ELESS:
case EGREATER:
case ELESSEQU:
case EGREATEREQU:
if (left->nodetype == EMONMIN) {
nd->nodetype = ComplementaryOp[nd->nodetype];
goto collapse;
}
break;
case EMUL:
case EDIV:
if (left->nodetype == EMONMIN)
goto collapse;
break;
case EEQU:
case ENOTEQU:
if (left->nodetype != ELOGNOT) {
collapse:
nd->u.diadic.left = left->u.monadic;
nd->u.diadic.right = right->u.monadic;
left->type = right->type = IROLinearNop;
changed = 1;
}
break;
case ELAND:
case ELOR:
if (left->nodetype == ELOGNOT) {
nd->nodetype = ComplementaryOp[nd->nodetype];
goto switchfather;
}
break;
case EAND:
case EOR:
if (
!IS_TYPE_FLOAT(nd->rtype) &&
!IS_TYPE_FLOAT(left->rtype) &&
!IS_TYPE_FLOAT(right->rtype) &&
left->nodetype != EMONMIN
)
{
nd->nodetype = ComplementaryOp[nd->nodetype];
goto switchfather;
}
break;
case EADD:
case ESUB:
if (
!IS_TYPE_FLOAT(nd->rtype) &&
!IS_TYPE_FLOAT(left->rtype) &&
!IS_TYPE_FLOAT(right->rtype) &&
left->nodetype == EMONMIN
)
{
switchfather:
switchFatherLeftMonadic(nd);
nd->u.diadic.right = right->u.monadic;
right->type = IROLinearNop;
changed = 1;
}
break;
}
if (changed) {
DoTransformations(nd);
DoTransformations11(nd);
DoTransformations12(nd);
DoTransformations13(nd);
}
break;
}
}
}
}
static void DoTransformations22(IROLinear *nd) {
IROLinear *left;
IROLinear *right;
IROLinear *ndtmp;
if (nd->type == IROLinearOp2Arg) {
left = nd->u.diadic.left;
right = nd->u.diadic.right;
if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype))
return;
if (!IRO_HasSideEffect(left) && !IRO_HasSideEffect(right)) {
if (left->type == IROLinearOp1Arg && left->nodetype == EMONMIN) {
switch (nd->nodetype) {
case ESUB:
case ESUBV:
nd->nodetype = ComplementaryOp[nd->nodetype];
switchFatherLeftMonadic(nd);
break;
case EADD:
case EADDV:
nd->nodetype = ComplementaryOp[nd->nodetype];
nd->u.diadic.left = right;
nd->u.diadic.right = left->u.monadic;
left->type = IROLinearNop;
DoTransformations(nd);
DoTransformations12(nd);
DoTransformations21(nd);
break;
case EDIV:
if (IRO_ExprsSameSemantically(left->u.monadic, right))
ReplaceExprWithConst(nd, cint64_negone);
break;
}
} else {
ndtmp = NULL;
if (left->type == IROLinearOp1Arg && IRO_ExprsSameSemantically(left->u.monadic, right))
ndtmp = left;
else if (right->type == IROLinearOp1Arg && IRO_ExprsSameSemantically(left, right->u.monadic))
ndtmp = right;
if (ndtmp) {
switch (nd->nodetype) {
case EAND:
if (ndtmp->nodetype == EBINNOT || ndtmp->nodetype == ELOGNOT)
ReplaceExprWithConst(nd, cint64_zero);
break;
case EANDASS:
if (ndtmp->nodetype == EBINNOT || ndtmp->nodetype == ELOGNOT) {
nd->nodetype = EASS;
ReplaceExprWithConst(right, cint64_zero);
nd->u.diadic.right->rtype = nd->rtype;
nd->u.diadic.right->u.node->rtype = nd->rtype;
}
break;
case EXOR:
case EOR:
if (ndtmp->nodetype == EBINNOT) {
ReplaceExprWithConst(nd, cint64_zero);
nd->u.node->data.intval = CInt64_Inv(nd->u.node->data.intval);
}
break;
case EXORASS:
case EORASS:
if (ndtmp->nodetype == EBINNOT) {
nd->nodetype = EASS;
ReplaceExprWithConst(right, cint64_zero);
right->u.node->data.intval = CInt64_Inv(right->u.node->data.intval);
nd->u.diadic.right->rtype = nd->rtype;
nd->u.diadic.right->u.node->rtype = nd->rtype;
}
break;
case ELOR:
if (ndtmp->nodetype == EBINNOT || ndtmp->nodetype == ELOGNOT)
ReplaceExprWithConst(nd, cint64_one);
break;
case ELAND:
if (ndtmp->nodetype == ELOGNOT)
ReplaceExprWithConst(nd, cint64_zero);
break;
case EDIV:
if (ndtmp->nodetype == EMONMIN)
ReplaceExprWithConst(nd, cint64_negone);
break;
case EDIVASS:
if (ndtmp->nodetype == EMONMIN) {
nd->nodetype = EASS;
ReplaceExprWithConst(right, cint64_negone);
nd->u.diadic.right->rtype = nd->rtype;
nd->u.diadic.right->u.node->rtype = nd->rtype;
}
break;
}
}
}
}
}
}
static void DoTransformations23(IROLinear *nd) {
Boolean changed;
Boolean isCompare;
UInt8 which;
IROLinear *left;
IROLinear *right;
CInt64 size;
CInt64 val;
if (nd->type == IROLinearOp2Arg && !IRO_HasSideEffect(nd)) {
left = nd->u.diadic.left;
right = nd->u.diadic.right;
if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype))
return;
isCompare = 0;
changed = 0;
which = 0;
switch (nd->nodetype) {
case ELESS:
case EGREATER:
case ELESSEQU:
case EGREATEREQU:
isCompare = 1;
case EADDV:
case EADD:
case EEQU:
case ENOTEQU:
case EAND:
case EOR:
if (left->type == IROLinearOp2Arg) {
if (IRO_ExprsSameSemantically(right, left->u.diadic.left))
which = 1;
else if (IRO_ExprsSameSemantically(right, left->u.diadic.right))
which = 2;
if (which) {
if (isCompare)
nd->nodetype = ComplementaryOp[nd->nodetype];
IRO_SwitchChildren(nd);
left = nd->u.diadic.left;
right = nd->u.diadic.right;
break;
}
}
case ESUBV:
case ESUB:
case EADDASS:
case ESUBASS:
case EANDASS:
case EORASS:
if (right->type == IROLinearOp2Arg) {
if (IRO_ExprsSameSemantically(left, right->u.diadic.left))
which = 1;
else if (IRO_ExprsSameSemantically(left, right->u.diadic.right))
which = 2;
}
break;
default:
goto done;
}
if (which) {
switch (right->nodetype) {
case EAND:
case EOR:
if (which == 2)
IRO_SwitchChildren(right);
if (
nd->nodetype == right->nodetype ||
(nd->nodetype == EANDASS && right->nodetype == EAND) ||
(nd->nodetype == EORASS && right->nodetype == EOR)
)
{
ReplaceExprWithRightChild(right);
changed = 1;
}
else if (
nd->nodetype == ComplementaryOp[right->nodetype] ||
(nd->nodetype == EANDASS && right->nodetype == EOR) ||
(nd->nodetype == EORASS && right->nodetype == EAND)
)
{
ReplaceExprWithLeftChild(nd);
}
break;
case EADD:
if (which == 2)
IRO_SwitchChildren(right);
switch (nd->nodetype) {
case EEQU:
case ENOTEQU:
ReplaceExprWithConst(left, cint64_zero);
ReplaceExprWithRightChild(right);
IRO_SwitchChildren(nd);
if (isCompare)
nd->nodetype = ComplementaryOp[nd->nodetype];
changed = 1;
break;
case ESUB:
case ESUBV:
ReplaceExprWithRightChild(right);
ReplaceExprWithMonaminRight(nd);
changed = 1;
break;
case ESUBASS:
ReplaceExprWithRightChild(right);
changed = 1;
break;
}
break;
case ESUB:
switch (nd->nodetype) {
case EEQU:
case ENOTEQU:
if (which == 1) {
ReplaceExprWithConst(left, cint64_zero);
ReplaceExprWithRightChild(right);
IRO_SwitchChildren(nd);
}
break;
case EADD:
case EADDV:
if (which == 2) {
ReplaceExprWithLeftChild(right);
ReplaceExprWithRightChild(nd);
}
break;
case ESUB:
case ESUBV:
if (which == 1) {
ReplaceExprWithRightChild(right);
ReplaceExprWithRightChild(nd);
}
break;
case EADDASS:
if (which == 2) {
nd->nodetype = EASS;
ReplaceExprWithLeftChild(right);
changed = 1;
}
break;
case ESUBASS:
if (which == 1) {
nd->nodetype = EASS;
ReplaceExprWithRightChild(right);
changed = 1;
}
break;
}
break;
}
}
done:
if (!changed) {
switch (nd->nodetype) {
case ESUB:
case ESUBV:
which = 0;
if (left->type == IROLinearOp2Arg) {
if (IRO_ExprsSameSemantically(right, left->u.diadic.left))
which = 1;
else if (IRO_ExprsSameSemantically(right, left->u.diadic.right))
which = 2;
}
if (which == 1) {
if (left->nodetype == ESUB) {
ReplaceExprWithMonaminRight(left);
ReplaceExprWithLeftChild(nd);
} else if (left->nodetype == EADD) {
ReplaceExprWithRightChild(left);
ReplaceExprWithLeftChild(nd);
}
} else if (which == 2) {
if (left->nodetype == EADD) {
ReplaceExprWithLeftChild(left);
ReplaceExprWithLeftChild(nd);
}
}
break;
}
switch (nd->nodetype) {
case ESHL:
case ESHR:
case ESHLASS:
case ESHRASS:
which = 0;
if (left->type == IROLinearOp2Arg) {
if (left->nodetype == ComplementaryOp[nd->nodetype] || left->nodetype == AssignmentOp[ComplementaryOp[nd->nodetype]]) {
if (IRO_IsIntConstant(right) && IRO_ExprsSameSemantically(right, left->u.diadic.right))
which = 2;
}
}
if (which == 2) {
val = right->u.node->data.intval;
if (left->nodetype == ESHR || left->nodetype == ESHRASS) {
ReplaceExprWithLeftChild(left);
nd->nodetype = (nd->nodetype == ESHL) ? EAND : EANDASS;
right->u.node->data.intval = CInt64_Shl(cint64_negone, val);
changed = 1;
} else if (IRO_IsUnsignedType(nd->rtype)) {
ReplaceExprWithLeftChild(left);
nd->nodetype = (nd->nodetype == ESHR) ? EAND : EANDASS;
if (nd->rtype->size < 8) {
CInt64_SetLong(&size, 64 - 8 * nd->rtype->size);
val = CInt64_Add(val, size);
}
right->u.node->data.intval = CInt64_ShrU(cint64_negone, val);
changed = 1;
}
}
break;
}
}
if (changed) {
DoTransformations(nd);
DoTransformations11(nd);
DoTransformations12(nd);
DoTransformations13(nd);
DoTransformations21(nd);
DoTransformations22(nd);
DoTransformations23(nd);
}
}
}
static void DoTransformations24(IROLinear *nd) {
IROLinear *left;
IROLinear *right;
UInt8 changed;
if (nd->type == IROLinearOp2Arg) {
left = nd->u.diadic.left;
right = nd->u.diadic.right;
if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype))
return;
if (left->type == IROLinearOp2Arg && right->type == IROLinearOp2Arg && !IRO_HasSideEffect(nd)) {
changed = 0;
if (IRO_ExprsSameSemantically(left->u.diadic.left, right->u.diadic.left)) {
if (left->nodetype == right->nodetype) {
switch (left->nodetype) {
case EADD:
if (nd->nodetype == ComplementaryOp[left->nodetype]) {
ReplaceExprWithRightChild(left);
ReplaceExprWithRightChild(right);
changed = 1;
}
break;
case ESUB:
if (nd->nodetype == ESUB || nd->nodetype == ESUBV) {
ReplaceExprWithRightChild(left);
ReplaceExprWithRightChild(right);
IRO_SwitchChildren(nd);
changed = 1;
}
break;
case EMUL:
switch (nd->nodetype) {
case EADD:
case ESUB:
PickCommonsubAtLeftLeft(nd);
changed = 3;
break;
}
break;
case EAND:
if (nd->nodetype == EXOR) {
PickCommonsubAtLeftLeft(nd);
changed = 3;
break;
}
case EOR:
if (nd->nodetype == left->nodetype) {
ReplaceExprWithRightChild(left);
changed = 1;
} else if (nd->nodetype == ComplementaryOp[left->nodetype]) {
PickCommonsubAtLeftLeft(nd);
changed = 3;
}
break;
}
} else if (left->nodetype == ComplementaryOp[right->nodetype]) {
switch (nd->nodetype) {
case ESUB:
case ESUBV:
switch (left->nodetype) {
case EADD:
nd->nodetype = ComplementaryOp[nd->nodetype];
ReplaceExprWithRightChild(left);
ReplaceExprWithRightChild(right);
changed = 1;
break;
case ESUB:
ReplaceExprWithMonaminRight(left);
ReplaceExprWithRightChild(right);
changed = 1;
break;
}
break;
case EAND:
case EOR:
if (left->nodetype == nd->nodetype)
ReplaceExprWithLeftChild(nd);
else if (right->nodetype == nd->nodetype)
ReplaceExprWithRightChild(nd);
break;
}
}
} else if (IRO_ExprsSameSemantically(left->u.diadic.right, right->u.diadic.left)) {
if (left->nodetype == right->nodetype) {
switch (left->nodetype) {
case EADD:
if (nd->nodetype == ComplementaryOp[left->nodetype]) {
ReplaceExprWithLeftChild(left);
ReplaceExprWithRightChild(right);
changed = 1;
}
break;
case EMUL:
switch (nd->nodetype) {
case EADD:
case ESUB:
PickCommonsubAtRightLeft(nd);
changed = 3;
break;
}
break;
case EAND:
if (nd->nodetype == EXOR) {
PickCommonsubAtRightLeft(nd);
changed = 3;
break;
}
case EOR:
if (nd->nodetype == left->nodetype) {
ReplaceExprWithLeftChild(left);
changed = 1;
} else if (nd->nodetype == ComplementaryOp[left->nodetype]) {
PickCommonsubAtRightLeft(nd);
changed = 3;
}
break;
}
} else if (left->nodetype == ComplementaryOp[right->nodetype]) {
switch (nd->nodetype) {
case ESUB:
case ESUBV:
if (left->nodetype == EADD) {
nd->nodetype = ComplementaryOp[nd->nodetype];
ReplaceExprWithLeftChild(left);
ReplaceExprWithRightChild(right);
changed = 1;
}
break;
case EADD:
case EADDV:
if (left->nodetype == ESUB) {
ReplaceExprWithLeftChild(left);
ReplaceExprWithRightChild(right);
changed = 1;
}
break;
case EAND:
case EOR:
if (left->nodetype == nd->nodetype)
ReplaceExprWithLeftChild(nd);
else if (right->nodetype == nd->nodetype)
ReplaceExprWithRightChild(nd);
break;
}
}
} else if (IRO_ExprsSameSemantically(left->u.diadic.left, right->u.diadic.right)) {
if (left->nodetype == right->nodetype) {
switch (left->nodetype) {
case EADD:
if (nd->nodetype == ComplementaryOp[left->nodetype]) {
ReplaceExprWithRightChild(left);
ReplaceExprWithLeftChild(right);
changed = 1;
}
break;
case ESUB:
switch (nd->nodetype) {
case EADDV:
case EADD:
nd->nodetype = ComplementaryOp[nd->nodetype];
ReplaceExprWithRightChild(left);
ReplaceExprWithLeftChild(right);
IRO_SwitchChildren(nd);
changed = 1;
break;
}
break;
case EMUL:
switch (nd->nodetype) {
case EADD:
case ESUB:
PickCommonsubAtLeftRight(nd);
changed = 2;
break;
}
break;
case EAND:
if (nd->nodetype == EXOR) {
PickCommonsubAtLeftRight(nd);
changed = 2;
break;
}
case EOR:
if (nd->nodetype == left->nodetype) {
ReplaceExprWithRightChild(left);
changed = 1;
} else if (nd->nodetype == ComplementaryOp[left->nodetype]) {
PickCommonsubAtLeftRight(nd);
changed = 2;
}
break;
}
} else if (left->nodetype == ComplementaryOp[right->nodetype]) {
switch (nd->nodetype) {
case EADD:
case EADDV:
if (left->nodetype == EADD) {
ReplaceExprWithRightChild(left);
ReplaceExprWithLeftChild(right);
changed = 1;
}
break;
case ESUB:
case ESUBV:
if (left->nodetype == ESUB) {
ReplaceExprWithMonaminRight(left);
ReplaceExprWithRightChild(right);
changed = 1;
}
break;
case EAND:
case EOR:
if (left->nodetype == nd->nodetype)
ReplaceExprWithLeftChild(nd);
else if (right->nodetype == nd->nodetype)
ReplaceExprWithRightChild(nd);
break;
}
}
} else if (IRO_ExprsSameSemantically(left->u.diadic.right, right->u.diadic.right)) {
if (left->nodetype == right->nodetype) {
switch (nd->nodetype) {
case ESUB:
switch (left->nodetype) {
case EADD:
case ESUB:
ReplaceExprWithLeftChild(left);
ReplaceExprWithLeftChild(right);
changed = 1;
}
case EADD:
switch (left->nodetype) {
case EMUL:
case ESHL:
PickCommonsubAtRightRight(nd);
changed = 2;
break;
}
break;
case EXOR:
switch (left->nodetype) {
case ESHL:
case ESHR:
case EAND:
PickCommonsubAtRightRight(nd);
changed = 2;
break;
}
break;
case EAND:
case EOR:
if (left->nodetype == nd->nodetype) {
ReplaceExprWithLeftChild(right);
changed = 1;
} else if (
left->nodetype == ComplementaryOp[nd->nodetype] ||
left->nodetype == ESHR ||
left->nodetype == ESHL
)
{
PickCommonsubAtRightRight(nd);
changed = 2;
}
break;
}
} else if (left->nodetype == ComplementaryOp[right->nodetype]) {
switch (nd->nodetype) {
case EADD:
case EADDV:
switch (left->nodetype) {
case EADD:
case ESUB:
ReplaceExprWithLeftChild(left);
ReplaceExprWithLeftChild(right);
changed = 1;
break;
}
break;
case EAND:
case EOR:
if (left->nodetype == nd->nodetype)
ReplaceExprWithLeftChild(nd);
else if (right->nodetype == nd->nodetype)
ReplaceExprWithRightChild(nd);
break;
}
}
}
if (changed) {
DoDiadic(nd);
if (changed == 2)
DoDiadic(nd->u.diadic.left);
else if (changed == 3)
DoDiadic(nd->u.diadic.right);
IRO_Dump("remove common op at: %d\n", nd->index);
}
}
}
}
static void DoTransformations25(IROLinear *nd) {
int changed = 0;
IROLinear *left;
IROLinear *right;
if (nd->type == IROLinearOp2Arg) {
left = nd->u.diadic.left;
right = nd->u.diadic.right;
if (
(left->type == IROLinearOp2Arg && (IS_TYPE_FLOAT(left->u.diadic.left->rtype) || IS_TYPE_FLOAT(left->u.diadic.right->rtype))) ||
(right->type == IROLinearOp2Arg && (IS_TYPE_FLOAT(right->u.diadic.left->rtype) || IS_TYPE_FLOAT(right->u.diadic.right->rtype)))
)
return;
switch (left->nodetype) {
case ELESS:
case EGREATER:
case ELESSEQU:
case EGREATEREQU:
case EEQU:
case ENOTEQU:
switch (nd->nodetype) {
case EEQU:
if (IRO_IsConstantOne(right)) {
ReplaceExprWithLeftChild(nd);
changed = 1;
} else if (IRO_IsConstantZero(right)) {
left->nodetype = ComplementaryOpLogical[left->nodetype];
ReplaceExprWithLeftChild(nd);
changed = 1;
}
break;
case ENOTEQU:
if (IRO_IsConstantOne(right)) {
left->nodetype = ComplementaryOpLogical[left->nodetype];
ReplaceExprWithLeftChild(nd);
changed = 1;
} else if (IRO_IsConstantZero(right)) {
ReplaceExprWithLeftChild(nd);
changed = 1;
}
break;
}
break;
case ELAND:
case ELOR:
switch (nd->nodetype) {
case EEQU:
if (IRO_IsConstantOne(right)) {
ReplaceExprWithLeftChild(nd);
changed = 1;
}
break;
case ENOTEQU:
if (IRO_IsConstantZero(right)) {
ReplaceExprWithLeftChild(nd);
changed = 1;
}
break;
}
break;
}
if (!changed) {
switch (right->nodetype) {
case ELESS:
case EGREATER:
case ELESSEQU:
case EGREATEREQU:
case EEQU:
case ENOTEQU:
switch (nd->nodetype) {
case EEQU:
if (IRO_IsConstantOne(left)) {
ReplaceExprWithRightChild(nd);
} else if (IRO_IsConstantZero(left)) {
right->nodetype = ComplementaryOpLogical[right->nodetype];
ReplaceExprWithRightChild(nd);
}
break;
case ENOTEQU:
if (IRO_IsConstantOne(left)) {
right->nodetype = ComplementaryOpLogical[right->nodetype];
ReplaceExprWithRightChild(nd);
} else if (IRO_IsConstantZero(left)) {
ReplaceExprWithRightChild(nd);
}
break;
}
break;
case ELAND:
case ELOR:
switch (nd->nodetype) {
case EEQU:
if (IRO_IsConstantOne(left)) {
ReplaceExprWithRightChild(nd);
}
break;
case ENOTEQU:
if (IRO_IsConstantZero(left)) {
ReplaceExprWithRightChild(nd);
}
break;
}
break;
}
}
}
}
static Boolean isOrderingOperator(ENodeType op) {
switch (op) {
case ELAND:
case ELOR:
case ECOMMA:
case ECOND:
case ECONDASS:
return 1;
default:
return 0;
}
}
static void RemoveUnreffed(IROLinear *nd) {
if (!(nd->flags & IROLF_Reffed)) {
switch (nd->type) {
case IROLinearOperand:
IRO_NopNonSideEffects(nd, 0);
break;
case IROLinearOp1Arg:
case IROLinearOp2Arg:
case IROLinearOp3Arg:
case IROLinearFunccall:
if (!isOrderingOperator(nd->nodetype))
IRO_NopNonSideEffects(nd, 0);
break;
}
}
}
static void RemoveRedundantMonadicOp(IROLinear *nd) {
IROLinear *nd2;
IROLinear *nd3;
if (nd->type == IROLinearOp1Arg && (nd2 = IRO_LocateFather(nd)) && nd2->nodetype == nd->nodetype) {
switch (nd->nodetype) {
case ELOGNOT:
if ((nd3 = IRO_LocateFather(nd2))) {
if (
nd3->rtype &&
TYPE_INTEGRAL(nd3->rtype)->integral == IT_BOOL &&
nd->u.monadic->rtype &&
TYPE_INTEGRAL(nd->u.monadic->rtype)->integral == IT_BOOL
)
goto remove;
if (nd3->type == IROLinearIf)
goto remove;
if (nd3->type == IROLinearIfNot)
goto remove;
if (nd3->type == IROLinearOp3Arg && nd == nd3->u.args3.a)
goto remove;
switch (nd3->nodetype) {
case ELOGNOT:
case ELAND:
case ELOR:
goto remove;
}
}
if (nd->u.monadic->type == IROLinearOp1Arg || nd->u.monadic->type == IROLinearOp2Arg) {
switch (nd->u.monadic->nodetype) {
case ELOGNOT:
case ELESS:
case EGREATER:
case ELESSEQU:
case EGREATEREQU:
case EEQU:
case ENOTEQU:
case ELAND:
case ELOR:
goto remove;
}
}
break;
case EMONMIN:
case EBINNOT:
remove:
IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd2, nd->u.monadic);
nd2->type = IROLinearNop;
nd->type = IROLinearNop;
break;
case ETYPCON:
if (TYPE_INTEGRAL(nd->rtype)->integral == IT_FLOAT) {
switch (TYPE_INTEGRAL(nd2->rtype)->integral) {
case IT_DOUBLE:
case IT_LONGDOUBLE:
switch (TYPE_INTEGRAL(nd->u.monadic->rtype)->integral) {
case IT_BOOL:
case IT_CHAR:
case IT_SCHAR:
case IT_UCHAR:
case IT_SHORT:
case IT_USHORT:
nd->type = IROLinearNop;
nd2->u.monadic = nd->u.monadic;
break;
}
break;
}
}
break;
}
}
}
static void ReverseOpForMonmin(IROLinear *nd) {
IROLinear *father;
if (
nd->type == IROLinearOp1Arg &&
nd->nodetype == EMONMIN &&
(father = IRO_LocateFather(nd)) &&
father->type == IROLinearOp2Arg &&
father->u.diadic.right == nd
)
{
switch (father->nodetype) {
case EADDV:
case ESUBV:
case EADD:
case ESUB:
case EADDASS:
case ESUBASS:
father->nodetype = ComplementaryOp[father->nodetype];
nd->type = IROLinearNop;
father->u.diadic.right = nd->u.monadic;
break;
}
}
}
static void DoDiadic(IROLinear *nd) {
RemoveUnreffed(nd);
DoTransformations(nd);
DoTransformations11(nd);
DoTransformations12(nd);
DoTransformations13(nd);
DoTransformations21(nd);
DoTransformations22(nd);
DoTransformations23(nd);
DoTransformations24(nd);
DoTransformations25(nd);
}
void IRO_DoTransformations(void) {
IROLinear *nd;
for (nd = IRO_FirstLinear; nd; nd = nd->next) {
switch (nd->type) {
case IROLinearOp2Arg:
DoDiadic(nd);
break;
case IROLinearOp1Arg:
RemoveUnreffed(nd);
RemoveRedundantMonadicOp(nd);
ReverseOpForMonmin(nd);
break;
case IROLinearOperand:
RemoveUnreffed(nd);
break;
}
}
IRO_CheckForUserBreak();
}
static Boolean ReconcileAssignments(IROLinear *nd1, IROLinear *nd2, IROList *list) {
IROLinear *copy;
Boolean result = 0;
int argCount;
int i;
IROLinear *tmp;
if (
(nd2->type == IROLinearOp1Arg && nd2->nodetype == ETYPCON) &&
!(nd1->type == IROLinearOp1Arg && nd1->nodetype == ETYPCON) &&
ReconcileAssignments(nd1, nd2->u.monadic, list)
)
{
result = 1;
}
if (
(nd1->type == IROLinearOp1Arg && nd1->nodetype == ETYPCON) &&
!(nd2->type == IROLinearOp1Arg && nd2->nodetype == ETYPCON) &&
ReconcileAssignments(nd1->u.monadic, nd2, list)
)
{
copy = IRO_NewLinear(IROLinearOp1Arg);
*copy = *nd2;
copy->index = IRO_NumLinear++;
copy->type = IROLinearOp1Arg;
copy->nodetype = ETYPCON;
copy->rtype = nd1->rtype;
copy->next = NULL;
copy->u.monadic = list->tail;
IRO_AddToList(copy, list);
result = 1;
}
if (nd1->type == nd2->type && nd1->nodetype == nd2->nodetype) {
copy = IRO_NewLinear(IROLinearNop);
*copy = *nd2;
copy->index = IRO_NumLinear++;
copy->rtype = nd1->rtype;
copy->next = NULL;
switch (nd1->type) {
case IROLinearOperand:
if (nd1->u.node->type == nd2->u.node->type) {
if (!(nd1->u.node->type == EOBJREF && nd1->u.node->data.objref != nd2->u.node->data.objref))
result = 1;
}
break;
case IROLinearOp1Arg:
if (ReconcileAssignments(nd1->u.monadic, nd2->u.monadic, list)) {
copy->u.monadic = list->tail;
result = 1;
}
break;
case IROLinearOp2Arg:
tmp = list->tail;
if (ReconcileAssignments(nd1->u.diadic.left, nd2->u.diadic.left, list)) {
copy->u.diadic.left = list->tail;
if (ReconcileAssignments(nd1->u.diadic.right, nd2->u.diadic.right, list)) {
copy->u.diadic.right = list->tail;
result = 1;
}
}
if (!result && !IRO_HasSideEffect(nd1) && !IRO_HasSideEffect(nd2)) {
if (nd1->nodetype == EMUL || nd1->nodetype == EADD || nd1->nodetype == EAND || nd1->nodetype == EXOR || nd1->nodetype == EOR) {
list->tail = tmp;
if (ReconcileAssignments(nd1->u.diadic.left, nd2->u.diadic.right, list)) {
copy->u.diadic.right = list->tail;
if (ReconcileAssignments(nd1->u.diadic.right, nd2->u.diadic.left, list)) {
copy->u.diadic.left = list->tail;
result = 1;
}
}
}
}
break;
case IROLinearOp3Arg:
if (ReconcileAssignments(nd1->u.args3.c, nd2->u.args3.c, list)) {
copy->u.args3.c = list->tail;
if (ReconcileAssignments(nd1->u.args3.b, nd2->u.args3.b, list)) {
copy->u.args3.b = list->tail;
if (ReconcileAssignments(nd1->u.args3.a, nd2->u.args3.a, list)) {
copy->u.args3.a = list->tail;
result = 1;
}
}
}
break;
case IROLinearFunccall:
argCount = nd1->u.funccall.argCount;
if (argCount == nd2->u.funccall.argCount) {
result = 1;
copy->u.funccall.args = oalloc(sizeof(IROLinear *) * argCount);
for (i = argCount - 1; i >= 0; i--) {
if (!ReconcileAssignments(nd1->u.funccall.args[i], nd2->u.funccall.args[i], list)) {
result = 0;
break;
}
copy->u.funccall.args[i] = list->tail;
}
if (result) {
if (!ReconcileAssignments(nd1->u.funccall.linear8, nd2->u.funccall.linear8, list)) {
result = 0;
break;
}
copy->u.funccall.linear8 = list->tail;
}
}
break;
}
if (result)
IRO_AddToList(copy, list);
}
return result;
}
static IROLinear *FrontendTransformSelfAssignmentToAssignment(IROLinear *nd) {
Statement *stmt;
IROList list;
IROLinearIRSave save;
IRO_SaveLinearIR(&save);
IRO_InitList(&list);
IRO_DuplicateExpr(nd, &list);
stmt = IRO_Delinearize(NULL, list.head);
CError_ASSERT(3550, stmt);
CError_ASSERT(3552, stmt->expr);
stmt->expr = CIRTrans_TransformOpAss(stmt->expr);
CError_ASSERT(3557, stmt->expr);
if (DoLinearize)
IRO_PreLinearize(stmt);
IRO_Linearize(stmt);
IRO_InitList(&list);
list.head = IRO_FirstLinear;
list.tail = IRO_LastLinear;
IRO_RestoreLinearIR(&save);
for (nd = list.head; nd; nd = nd->next) {
if (!(nd->flags & IROLF_Reffed) && IRO_IsAssignment(nd))
break;
}
return nd;
}
static Type *PromotedIntegralType(Type *type) {
CError_ASSERT(3586, IS_TYPE_ENUM(type) || IS_TYPE_INT(type));
if (IS_TYPE_ENUM(type))
type = TYPE_ENUM(type)->enumtype;
if (TYPE_INTEGRAL(type)->integral < IT_INT) {
if (IRO_IsUnsignedType(type))
return TYPE(&stunsignedint);
else
return TYPE(&stsignedint);
} else {
return type;
}
}
static Boolean TransformMonadicSelfAssignmentToDiadicSelfAssignment(IROLinear *nd) {
ENodeType t;
ENodeType newtype;
IROLinear *incExpr;
IROLinear *varExpr;
t = nd->nodetype;
if (IRO_IsAssignment(nd) && IRO_IsModifyOp[t]) {
incExpr = NULL;
varExpr = NULL;
newtype = MAXEXPR;
if (
nd->type == IROLinearOp1Arg &&
(t == EPOSTINC || t == EPOSTDEC || t == EPREINC || t == EPREDEC) &&
(!(nd->flags & IROLF_Reffed) || t == EPREINC || t == EPREDEC)
)
{
Type *type = nd->rtype;
TypeType typetype = type->type;
varExpr = nd->u.monadic;
if (typetype == TYPEINT || typetype == TYPEENUM) {
incExpr = IRO_NewIntConst(cint64_one, PromotedIntegralType(type));
} else if (typetype == TYPEPOINTER || typetype == TYPEARRAY || typetype == TYPEMEMBERPOINTER) {
Type *inner = NULL;
CInt64 val = cint64_zero;
if (typetype == TYPEPOINTER || typetype == TYPEARRAY)
inner = TPTR_TARGET(type);
else if (typetype == TYPEMEMBERPOINTER)
inner = TYPE_MEMBER_POINTER(type)->ty1;
if (inner)
CInt64_SetLong(&val, inner->size);
if (!CInt64_IsZero(&val)) {
incExpr = IRO_NewIntConst(val, TYPE(&stsignedlong));
} else {
return 0;
}
} else if (typetype == TYPEFLOAT) {
Float fval;
fval = CMach_CalcFloatConvertFromInt(type, cint64_one);
incExpr = IRO_NewFloatConst(fval, nd->rtype);
} else {
return 0;
}
if (t == EPOSTINC || t == EPREINC)
newtype = EADDASS;
else
newtype = ESUBASS;
}
if (
varExpr &&
incExpr &&
newtype != MAXEXPR &&
varExpr->u.diadic.left &&
varExpr->u.diadic.left->type == IROLinearOperand &&
varExpr->u.diadic.left->u.node &&
varExpr->u.diadic.left->u.node->type == EOBJREF &&
!IRO_HasSideEffect(varExpr)
)
{
incExpr->flags |= IROLF_Reffed;
nd->nodetype = newtype;
nd->u.diadic.right = incExpr;
nd->type = IROLinearOp2Arg;
IRO_Paste(incExpr, incExpr, nd);
return 1;
}
}
return 0;
}
Boolean IRO_TransformSelfAssignmentToAssignment(IROLinear *nd) {
ENodeType nonAssOp;
IROLinear *left;
IROLinear *right;
ENodeType nodetype;
IROLinear *nonAss;
IROLinear *dupLeft;
IROLinear *last;
IROList list1;
IROList list2;
nodetype = nd->nodetype;
if (
IRO_IsAssignment(nd) &&
IRO_IsModifyOp[nodetype] &&
nd->type == IROLinearOp1Arg &&
TransformMonadicSelfAssignmentToDiadicSelfAssignment(nd)
)
nodetype = nd->nodetype;
if (
IRO_IsAssignment(nd) &&
IRO_IsModifyOp[nodetype] &&
nd->type == IROLinearOp2Arg &&
IRO_NonAssignmentOp[nodetype] != MAXEXPR
)
{
left = nd->u.diadic.left;
right = nd->u.diadic.right;
nonAssOp = IRO_NonAssignmentOp[nodetype];
if (
left &&
right &&
nonAssOp != MAXEXPR &&
left->u.monadic &&
left->u.monadic->type == IROLinearOperand &&
left->u.monadic->u.node &&
left->u.monadic->u.node->type == EOBJREF &&
!IRO_HasSideEffect(left)
)
{
IRO_InitList(&list1);
dupLeft = IRO_DuplicateExpr(left, &list1);
if (left->rtype != right->rtype) {
IROLinear *tmp = IRO_NewLinear(IROLinearOp1Arg);
tmp->nodetype = ETYPCON;
tmp->flags |= IROLF_Reffed;
tmp->rtype = right->rtype;
tmp->index = ++IRO_NumLinear;
tmp->u.monadic = dupLeft;
IRO_AddToList(tmp, &list1);
dupLeft = tmp;
}
nonAss = IRO_NewLinear(IROLinearOp2Arg);
nonAss->nodetype = nonAssOp;
nonAss->flags |= IROLF_Reffed;
nonAss->rtype = dupLeft->rtype;
nonAss->index = ++IRO_NumLinear;
nonAss->u.diadic.left = dupLeft;
nonAss->u.diadic.right = right;
IRO_AddToList(nonAss, &list1);
if (left->rtype != right->rtype) {
IROLinear *tmp = IRO_NewLinear(IROLinearOp1Arg);
tmp->nodetype = ETYPCON;
tmp->flags |= IROLF_Reffed;
tmp->rtype = left->rtype;
tmp->index = ++IRO_NumLinear;
tmp->u.monadic = nonAss;
IRO_AddToList(tmp, &list1);
nonAss = tmp;
}
IRO_InitList(&list2);
last = FrontendTransformSelfAssignmentToAssignment(nd);
if (
last &&
last->type == IROLinearOp2Arg &&
ReconcileAssignments(last->u.diadic.right, nonAss, &list2)
)
{
IRO_NopOut(nd->u.diadic.right);
nd->nodetype = EASS;
nd->u.diadic.right = list2.tail;
nd->type = IROLinearOp2Arg;
IRO_Paste(list2.head, list2.tail, nd);
return 1;
}
}
}
return 0;
}
static void AddAddend(ENode *expr) {
if (expr->type == EADD) {
AddAddend(expr->data.diadic.left);
AddAddend(expr->data.diadic.right);
} else {
ENodeList *list = oalloc(sizeof(ENodeList));
list->node = expr;
list->next = NULL;
if (FirstAddend)
LastAddend->next = list;
else
FirstAddend = list;
LastAddend = list;
}
}
static ENode *CombineConstants(ENode *expr) {
ENode *addend;
ENodeList *el;
ENode *result;
ENode *var;
Type *type;
ENode *tmp;
ENodeList *prev;
CInt64 val;
FirstAddend = LastAddend = NULL;
AddAddend(expr->data.diadic.left);
AddAddend(expr->data.diadic.right);
// these variable names are courtesy of the resource fork in abort_exit.c
el = FirstAddend;
prev = NULL;
var = NULL;
while (el) {
addend = el->node;
if (addend->type == EOBJREF) {
var = addend;
if (prev)
prev->next = el->next;
else
FirstAddend = el->next;
break;
}
prev = el;
el = el->next;
}
if (!var) {
el = FirstAddend;
prev = NULL;
while (el) {
addend = el->node;
if (addend->type == EINDIRECT) {
var = addend;
if (prev)
prev->next = el->next;
else
FirstAddend = el->next;
break;
}
prev = el;
el = el->next;
}
}
prev = NULL;
CInt64_SetLong(&val, 0);
type = NULL;
for (el = FirstAddend; el; el = el->next) {
addend = el->node;
if (addend->type == EINTCONST && addend->rtype) {
if (!type || type->size < addend->rtype->size)
type = addend->rtype;
val = CInt64_Add(val, addend->data.intval);
if (prev)
prev->next = el->next;
else
FirstAddend = el->next;
} else if (addend->type == EMUL && addend->data.diadic.right->type == EINTCONST && addend->rtype) {
if (!type || type->size < addend->rtype->size)
type = addend->rtype;
tmp = addend->data.diadic.left;
if (tmp->type == EADD && tmp->data.diadic.right->type == EINTCONST) {
val = CInt64_Add(val, CInt64_MulU(tmp->data.diadic.right->data.intval, addend->data.diadic.right->data.intval));
addend->data.diadic.left = tmp->data.diadic.left;
}
prev = el;
} else {
prev = el;
}
}
result = NULL;
if (var) {
result = var;
if (!CInt64_IsZero(&val)) {
result = IRO_NewENode(EADD);
result->data.diadic.left = var;
result->data.diadic.right = IRO_NewENode(EINTCONST);
result->data.diadic.right->data.intval = val;
result->data.diadic.right->rtype = type;
result->rtype = var->rtype;
result->cost = 1;
CInt64_SetLong(&val, 0);
}
}
for (el = FirstAddend; el; el = el->next) {
addend = el->node;
if (result) {
tmp = IRO_NewENode(EADD);
tmp->data.diadic.left = result;
tmp->data.diadic.right = addend;
tmp->cost = result->cost + 1;
tmp->rtype = result->rtype;
result = tmp;
} else {
result = addend;
}
}
if (!CInt64_IsZero(&val)) {
tmp = IRO_NewENode(EADD);
tmp->data.diadic.left = result;
tmp->data.diadic.right = IRO_NewENode(EINTCONST);
tmp->data.diadic.right->data.intval = val;
tmp->data.diadic.right->rtype = type;
tmp->cost = result->cost + 1;
tmp->rtype = result->rtype;
result = tmp;
}
return result;
}
static ENode *TransformExprNode(ENode *expr) {
ENode *left;
ENode *right;
switch (expr->type) {
case EINDIRECT:
if (ENODE_IS(expr->data.monadic, EADD))
expr->data.monadic = CombineConstants(expr->data.monadic);
break;
case EMUL:
case EADD:
case EAND:
case EXOR:
case EOR:
if (
IS_TYPE_INT(expr->rtype) &&
!ENODE_IS(right = expr->data.diadic.right, EINTCONST) &&
ENODE_IS(left = expr->data.diadic.left, EINTCONST)
)
{
expr->data.diadic.left = right;
expr->data.diadic.right = left;
}
break;
case EEQU:
case ENOTEQU:
if (
IS_TYPE_INT(expr->rtype) &&
!ENODE_IS(left = expr->data.diadic.right, EINTCONST) &&
ENODE_IS(right = expr->data.diadic.left, EINTCONST)
)
{
expr->data.diadic.left = left;
expr->data.diadic.right = right;
}
if (
ENODE_IS(expr->data.diadic.right, EINTCONST) &&
ENODE_IS(left = expr->data.diadic.left, EBINNOT)
)
{
expr->data.diadic.left = left->data.monadic;
left->data.monadic = expr->data.diadic.right;
expr->data.diadic.right = left;
}
break;
}
return expr;
}
static ENode *TransformExprTree(ENode *expr) {
ENodeList *list;
switch (expr->type) {
ENODE_CASE_MONADIC:
expr->data.monadic = TransformExprTree(expr->data.monadic);
break;
ENODE_CASE_DIADIC_ALL:
expr->data.diadic.left = TransformExprTree(expr->data.diadic.left);
expr->data.diadic.right = TransformExprTree(expr->data.diadic.right);
break;
case EFUNCCALL:
case EFUNCCALLP:
TransformExprTree(expr->data.funccall.funcref);
for (list = expr->data.funccall.args; list; list = list->next)
TransformExprTree(list->node);
break;
case ECOND:
TransformExprTree(expr->data.cond.cond);
TransformExprTree(expr->data.cond.expr1);
TransformExprTree(expr->data.cond.expr2);
break;
case ENULLCHECK:
TransformExprTree(expr->data.nullcheck.nullcheckexpr);
TransformExprTree(expr->data.nullcheck.condexpr);
break;
}
return TransformExprNode(expr);
}
static void FoldConstantsinAssociativeExprs(ENode *expr) {
short nodetype1;
short nodetype2;
short nodetype3;
Boolean changed;
short op;
CInt64 val1;
CInt64 val2;
CInt64 tmpval;
if (
(
expr->type == EADD ||
expr->type == EMUL ||
expr->type == EAND ||
expr->type == EXOR ||
expr->type == EOR ||
expr->type == ESHL ||
expr->type == ESHR
) &&
IS_TYPE_INT(expr->rtype) &&
expr->data.diadic.right->type == EINTCONST
)
{
do {
changed = 0;
if (
expr->data.diadic.left->type == expr->type &&
expr->data.diadic.left->data.diadic.right->type == EINTCONST
)
{
val1 = expr->data.diadic.right->data.intval;
val2 = expr->data.diadic.left->data.diadic.right->data.intval;
switch (expr->type) {
case EADD:
case ESHL:
op = '+';
break;
case ESHR:
op = '+';
if (!IRO_IsUnsignedType(expr->rtype)) {
CInt64_SetLong(&tmpval, expr->rtype->size * 8);
if (CInt64_GreaterEqualU(val1, tmpval) || CInt64_GreaterEqualU(val2, tmpval))
return;
if (CInt64_GreaterEqualU(CMach_CalcIntDiadic(expr->rtype, val1, '+', val2), tmpval)) {
val1 = CInt64_Sub(tmpval, cint64_one);
val2 = cint64_zero;
}
}
break;
case EMUL:
op = '*';
break;
case EAND:
op = '&';
break;
case EOR:
op = '|';
break;
case EXOR:
op = '^';
break;
default:
return;
}
expr->data.diadic.right->data.intval = CMach_CalcIntDiadic(expr->rtype, val1, op, val2);
expr->data.diadic.left = expr->data.diadic.left->data.diadic.left;
changed = 1;
} else if (
((nodetype1 = expr->type) == EAND || nodetype1 == EOR) &&
((nodetype2 = expr->data.diadic.left->type) == EAND || nodetype2 == EOR) &&
((nodetype3 = expr->data.diadic.left->data.diadic.left->type) == EAND || nodetype3 == EOR) &&
expr->data.diadic.left->data.diadic.left->data.diadic.right->type == EINTCONST
)
{
val1 = expr->data.diadic.right->data.intval;
if (CInt64_Equal(val1, expr->data.diadic.left->data.diadic.left->data.diadic.right->data.intval)) {
if (nodetype1 == nodetype3) {
expr->data.diadic.left->data.diadic.left = expr->data.diadic.left->data.diadic.left->data.diadic.left;
changed = 1;
} else if (nodetype2 == nodetype3) {
*expr = *expr->data.diadic.right;
changed = 1;
} else {
expr->data.diadic.left = expr->data.diadic.left->data.diadic.right;
changed = 1;
}
}
}
} while (changed);
}
}
static void TransformExprTree1(ENode *expr) {
ENodeList *list;
switch (expr->type) {
ENODE_CASE_MONADIC:
TransformExprTree1(expr->data.monadic);
break;
ENODE_CASE_DIADIC_ALL:
TransformExprTree1(expr->data.diadic.left);
TransformExprTree1(expr->data.diadic.right);
break;
case EFUNCCALL:
case EFUNCCALLP:
TransformExprTree1(expr->data.funccall.funcref);
for (list = expr->data.funccall.args; list; list = list->next)
TransformExprTree1(list->node);
break;
case ECOND:
TransformExprTree1(expr->data.cond.cond);
TransformExprTree1(expr->data.cond.expr1);
TransformExprTree1(expr->data.cond.expr2);
break;
case ENULLCHECK:
TransformExprTree1(expr->data.nullcheck.nullcheckexpr);
TransformExprTree1(expr->data.nullcheck.condexpr);
break;
}
FoldConstantsinAssociativeExprs(expr);
}
static int RemoveRedundantBitOperations(ENode *expr) {
Boolean a;
Boolean b;
if (expr->type == ExprType) {
a = RemoveRedundantBitOperations(expr->data.diadic.left);
b = RemoveRedundantBitOperations(expr->data.diadic.right);
return a & b;
}
if (expr->type == EINDIRECT) {
if (expr->data.monadic->type == EOBJREF) {
if (!OperandObject) {
OperandObject = expr->data.monadic->data.objref;
IndirectRef = expr;
return 1;
} else {
return expr->data.monadic->data.objref == OperandObject;
}
} else {
return 0;
}
}
if (expr->type == EINTCONST) {
if (FirstTime) {
OperandConst = expr->data.intval;
FirstTime = 0;
} else if (ExprType == EAND) {
OperandConst = CInt64_And(expr->data.intval, OperandConst);
} else if (ExprType == EOR) {
OperandConst = CInt64_Or(expr->data.intval, OperandConst);
} else if (ExprType == EXOR) {
OperandConst = CInt64_Xor(expr->data.intval, OperandConst);
}
return 1;
}
return 0;
}
static void TransformExprTree2(ENode *expr) {
ENodeList *list;
switch (expr->type) {
ENODE_CASE_MONADIC:
TransformExprTree2(expr->data.monadic);
break;
ENODE_CASE_DIADIC_ALL:
TransformExprTree2(expr->data.diadic.left);
TransformExprTree2(expr->data.diadic.right);
break;
case EFUNCCALL:
case EFUNCCALLP:
TransformExprTree2(expr->data.funccall.funcref);
for (list = expr->data.funccall.args; list; list = list->next)
TransformExprTree2(list->node);
break;
case ECOND:
TransformExprTree2(expr->data.cond.cond);
TransformExprTree2(expr->data.cond.expr1);
TransformExprTree2(expr->data.cond.expr2);
break;
case ENULLCHECK:
TransformExprTree2(expr->data.nullcheck.nullcheckexpr);
TransformExprTree2(expr->data.nullcheck.condexpr);
break;
}
if (
ENODE_IS3(expr, EAND, EOR, EXOR) &&
(expr->type == expr->data.diadic.left->type || expr->type == expr->data.diadic.right->type)
)
{
OperandObject = NULL;
ExprType = expr->type;
FirstTime = 1;
IndirectRef = NULL;
if (RemoveRedundantBitOperations(expr)) {
expr->data.diadic.left = IndirectRef;
expr->data.diadic.right->type = EINTCONST;
expr->data.diadic.right->data.intval = OperandConst;
}
}
}
static void PullOutPostOps(Statement *stmt, ENode **pExpr) {
ENode *ind;
ENode *inner;
Statement *newStmt;
switch ((*pExpr)->type) {
ENODE_CASE_MONADIC:
if ((*pExpr)->type != EFORCELOAD)
PullOutPostOps(stmt, &(*pExpr)->data.monadic);
if (ENODE_IS2(*pExpr, EPOSTINC, EPOSTDEC)) {
inner = (*pExpr)->data.monadic;
if (
ENODE_IS(inner, EINDIRECT) &&
inner->rtype &&
!CParser_IsVolatile(inner->rtype, ENODE_QUALS(inner)) &&
ENODE_IS(inner->data.monadic, EOBJREF) &&
!is_volatile_object(inner->data.monadic->data.objref)
)
{
newStmt = lalloc(sizeof(Statement));
memset(newStmt, 0, sizeof(Statement));
newStmt->type = ST_EXPRESSION;
newStmt->expr = *pExpr;
newStmt->dobjstack = stmt->dobjstack;
newStmt->sourceoffset = stmt->sourceoffset;
newStmt->sourcefilepath = stmt->sourcefilepath;
newStmt->value = stmt->value;
newStmt->flags = stmt->flags;
newStmt->next = stmt->next;
stmt->next = newStmt;
ind = IRO_NewENode(EINDIRECT);
*ind = *inner;
ind->data.monadic = IRO_NewENode(EOBJREF);
*ind->data.monadic = *inner->data.monadic;
*pExpr = ind;
}
}
break;
ENODE_CASE_DIADIC_ALL:
if (ENODE_IS(*pExpr, ECOND))
break;
if (ENODE_IS(*pExpr, ECOMMA))
break;
if (ENODE_IS(*pExpr, ELOR))
break;
if (ENODE_IS(*pExpr, ELAND))
break;
if (ENODE_IS(*pExpr, ENULLCHECK))
break;
PullOutPostOps(stmt, &(*pExpr)->data.diadic.left);
PullOutPostOps(stmt, &(*pExpr)->data.diadic.right);
break;
}
}
void IRO_TransformTree(Statement *statements) {
Statement *stmt;
Statement *next;
for (stmt = statements; stmt; stmt = next) {
next = stmt->next;
switch (stmt->type) {
case ST_EXPRESSION:
case ST_SWITCH:
case ST_IFGOTO:
case ST_IFNGOTO:
case ST_RETURN:
if (stmt->expr) {
stmt->expr = TransformExprTree(stmt->expr);
TransformExprTree2(stmt->expr);
TransformExprTree1(stmt->expr);
}
break;
}
}
IRO_CheckForUserBreak();
}