diff options
Diffstat (limited to 'compiler_and_linker/FrontEnd/Optimizer/IroTransform.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/Optimizer/IroTransform.c | 2794 |
1 files changed, 2794 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroTransform.c b/compiler_and_linker/FrontEnd/Optimizer/IroTransform.c new file mode 100644 index 0000000..8a4af16 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroTransform.c @@ -0,0 +1,2794 @@ +#include "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 "IroDump.h" +#include "IroLinearForm.h" +#include "IroMalloc.h" +#include "IroPointerAnalysis.h" +#include "IROUseDef.h" +#include "IroUtil.h" +#include "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)->bitlength; + 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(); +} |