#include "compiler/IroExprRegeneration.h" #include "compiler/IroCSE.h" #include "compiler/IroDump.h" #include "compiler/IroFlowgraph.h" #include "compiler/IroLinearForm.h" #include "compiler/IroSubable.h" #include "compiler/IroTransform.h" #include "compiler/IROUseDef.h" #include "compiler/IroUtil.h" #include "compiler/IroVars.h" #include "compiler/CDecl.h" #include "compiler/CExpr.h" #include "compiler/CFunc.h" #include "compiler/CInt64.h" #include "compiler/CMachine.h" #include "compiler/CParser.h" #include "compiler/objects.h" // forward decls static void GetExprUses(IROLinear *linear, Boolean isEntry); static void RebuildPossibleCondExpression(IRONode *fnode); static void AddNodeAndSuccessorsRecursively(IRONodes *nodes, IRONode *fnode1, IRONode *fnode2); static Boolean FindFlowgraphNodeThatStartsWithLabel(CLabel *label, IRONode **result1, IRONode **result2) { IRONode *prev; IRONode *iter; prev = IRO_FirstNode; if (prev != NULL) iter = prev->nextnode; while (iter) { if (iter->first->type == IROLinearLabel && iter->first->u.label.label == label) { *result1 = iter; *result2 = prev; return 1; } prev = iter; iter = iter->nextnode; } return 0; } static IROLinear *FindLastDiadicTopLevelAssignmentInFlowgraphNode(IRONode *fnode) { IROLinear *scan; IROLinear *result; result = NULL; for (scan = fnode->first; scan != fnode->last->next; scan = scan->next) { if (scan->type == IROLinearOp2Arg && scan->nodetype == EASS && !(scan->flags & IROLF_Reffed)) result = scan; } return result; } static Boolean RewriteUse(IROUse *use, ENode *enode, IROLinear *nd, Boolean flag) { IROLinear *father; IROLinear *father2; if ( use && use->x1C && use->linear && use->linear->type == IROLinearOperand && use->linear->u.node->type == EOBJREF && use->linear->u.node->data.objref == enode->data.objref && (father = IRO_LocateFather(use->linear)) && father->type == IROLinearOp1Arg && father->nodetype == EINDIRECT && father->rtype == nd->rtype && (father2 = IRO_LocateFather(father)) && ((father2->type != IROLinearOp1Arg && father2->type != IROLinearOp2Arg) || !IRO_IsModifyOp[father2->nodetype]) ) { if (flag) IRO_LocateFather_Cut_And_Paste(father, nd); return 1; } return 0; } #ifdef __MWERKS__ #pragma options align=mac68k #endif static struct { jmp_buf buf; UInt16 index; Boolean flag; } scuai; #ifdef __MWERKS__ #pragma options align=reset #endif static void StatementContainsUseAction(IROLinear *linear, Boolean isFirst) { if (isFirst && linear->index == scuai.index) { scuai.flag = 1; longjmp(scuai.buf, 1); } } static Boolean StatementContainsUse(IROLinear *a, IROLinear *b) { memset(&scuai, 0, sizeof(scuai)); scuai.index = b->index; scuai.flag = 0; if (!setjmp(scuai.buf)) IRO_WalkInts(a, a, StatementContainsUseAction); return scuai.flag; } #ifdef __MWERKS__ #pragma options align=mac68k #endif static struct { jmp_buf buf; Boolean flag; } scseai; #ifdef __MWERKS__ #pragma options align=reset #endif static void StatementContainsSideEffectAction(IROLinear *linear, Boolean isFirst) { if (isFirst) { switch (linear->type) { case IROLinearOperand: case IROLinearOp1Arg: case IROLinearOp2Arg: case IROLinearOp3Arg: case IROLinearFunccall: case IROLinearAsm: if (IRO_HasSideEffect(linear)) { scseai.flag = 1; longjmp(scseai.buf, 1); } break; } } } static Boolean StatementContainsSideEffect(IROLinear *linear) { memset(&scseai, 0, sizeof(scseai)); scseai.flag = 0; if (!setjmp(scseai.buf)) IRO_WalkInts(linear, linear, StatementContainsSideEffectAction); return scseai.flag; } static Boolean HasSideEffectsBeforeUse(IRONode *fnode1, IRONode *fnode2, IRONode *fnode3, IROLinear *nd, Boolean flag) { IRONode *fnode; IROLinear *scannd; UInt16 i; if (fnode1 != fnode3) { if (flag) { for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) fnode->x3C = 0; } else if (fnode1->x3C) { return 0; } fnode1->x3C = 1; } for (scannd = fnode1->first; scannd && scannd != fnode1->last->next; scannd = scannd->next) { if (!(scannd->flags & IROLF_Reffed)) { if (StatementContainsUse(scannd, nd)) return 0; if (StatementContainsSideEffect(scannd)) return 1; } } if (fnode1 != fnode3) { for (i = 0; i < fnode1->numsucc; i++) { if (HasSideEffectsBeforeUse(IRO_NodeTable[fnode1->succ[i]], fnode2, fnode3, nd, 0)) return 1; } } return 0; } static Boolean UsesAKilledVarBeforeUse(IRONode *fnode1, IRONode *fnode2, IRONode *fnode3, IROLinear *nd, BitVector *bv, Boolean flag) { IRONode *fnode; UInt16 i; IROLinear *scannd; if (fnode1 != fnode3) { if (flag) { for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) fnode->x3C = 0; } else if (fnode1->x3C) { return 0; } fnode1->x3C = 1; } for (scannd = fnode1->first; scannd && scannd != fnode1->last->next; scannd = scannd->next) { if (!(scannd->flags & IROLF_Reffed)) { if (StatementContainsUse(scannd, nd)) return 0; Bv_Clear(IRO_VarKills); IRO_WalkInts(scannd, scannd, GetExprUses); if (Bv_BitsInCommon(bv, IRO_VarKills)) return 1; } } if (fnode1 != fnode3) { for (i = 0; i < fnode1->numsucc; i++) { if (UsesAKilledVarBeforeUse(IRO_NodeTable[fnode1->succ[i]], fnode2, fnode3, nd, bv, 0)) return 1; } } return 0; } static void GetExprUses(IROLinear *linear, Boolean isEntry) { Object *obj; VarRecord *var; if (isEntry) { if (linear->type == IROLinearOperand && linear->u.node->type == EOBJREF) { obj = linear->u.node->data.objref; if ((linear->flags & IROLF_Ind) && (!(linear->flags & IROLF_Assigned) || (linear->flags & IROLF_Used))) { if ((var = IRO_FindVar(obj, 0, 1))) Bv_SetBit(var->index, IRO_VarKills); } } } } static void GetExprKills(IROLinear *linear, Boolean isEntry) { if (isEntry) IRO_GetKills(linear); } static void CheckUnorderedRegionForSideEffectsAndUses(IROLinear *nd, BitVector *bv1, BitVector *bv2, Boolean *result) { if (IRO_HasSideEffect(nd)) { *result = 1; } else { Bv_Clear(bv2); Bv_Clear(IRO_VarKills); IRO_WalkTree(nd, GetExprUses); Bv_Or(IRO_VarKills, bv2); if (Bv_BitsInCommon(bv1, bv2)) *result = 1; } } static void CheckUnorderedRegionsForSideEffectsAndUses(IROLinear *nd1, IROLinear *nd2, BitVector *bv1, BitVector *bv2, Boolean *result) { int i; switch (nd1->type) { case IROLinearOp2Arg: if (nd1->nodetype != ELAND && nd1->nodetype != ELOR && nd1->nodetype != ECOMMA) { if (nd1->u.diadic.left != nd2) CheckUnorderedRegionForSideEffectsAndUses(nd1->u.diadic.left, bv1, bv2, result); if (nd1->u.diadic.right != nd2) CheckUnorderedRegionForSideEffectsAndUses(nd1->u.diadic.right, bv1, bv2, result); } break; case IROLinearFunccall: if (nd1->u.funccall.linear8 != nd2) CheckUnorderedRegionForSideEffectsAndUses(nd1->u.funccall.linear8, bv1, bv2, result); for (i = 0; !*result && i < nd1->u.funccall.argCount; i++) { if (nd1->u.funccall.args[i] != nd2) CheckUnorderedRegionForSideEffectsAndUses(nd1->u.funccall.args[i], bv1, bv2, result); } break; } } static Boolean CheckThenOrElseBranch(IRONode *fnode1, IRONode *fnode2, IROLinear *nd, Boolean flag) { IRONode *fnode; IROLinear *scannd; IRONodes nodes; Boolean result; IROFlowgraph_sub_4C2140(&nodes); for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) fnode->x3C = 0; AddNodeAndSuccessorsRecursively(&nodes, fnode1, fnode2); while (IROFlowgraph_sub_4C2040(&nodes)) { fnode = IRO_NodeTable[IROFlowgraph_sub_4C2100(&nodes)]; if (fnode) { if (!Bv_IsBitSet(fnode1->index, fnode->dom)) { result = 0; goto done; } for (scannd = fnode->first; scannd && scannd != fnode->last->next; scannd = scannd->next) { if (!nd || scannd != nd) { if (!flag || (scannd->type != IROLinearReturn)) { if (fnode->numpred == 2 && scannd->type == IROLinearLabel) RebuildPossibleCondExpression(fnode); if (scannd->type != IROLinearNop && scannd->type != IROLinearLabel && scannd->type != IROLinearGoto && !(scannd->flags & IROLF_Reffed)) { result = 0; goto done; } } } } } } result = 1; done: IROFlowgraph_sub_4C20E0(&nodes); return result; } static void RebuildPossibleCondExpression(IRONode *fnode) { IRONode *pred1; IRONode *pred2; IRONode *r30; IROLinear *leftAss; IROLinear *rightAss; IROLinear *r27; IROLinear *r13; IROLinear *var_58; IRONode *left; IRONode *right; IRONode *r24; ENode *r23; IRODef *r22; IRODef *r21; IRODef *def; IROUse *use; UInt32 r20; UInt32 r19; Boolean r18; Boolean r17; UInt32 i; Boolean compareType; Type *var_60; IROLinear copy1; IROLinear copy2; IROLinear copy3; if ( !fnode || fnode->numpred != 2 || !fnode->first || fnode->first->type != IROLinearLabel ) return; pred1 = IRO_NodeTable[fnode->pred[0]]; pred2 = IRO_NodeTable[fnode->pred[1]]; if ( !pred1 || !pred2 || pred1->numsucc != 1 || pred2->numsucc != 1 ) return; r24 = NULL; for (i = 0; i < IRO_NumNodes; i++) { if ( Bv_IsBitSet(i, fnode->dom) && (r24 = IRO_NodeTable[i]) && r24->last && (r24->last->type == IROLinearIf || r24->last->type == IROLinearIfNot) && r24->last->u.label.label && r24->numsucc == 2 ) { if (Bv_IsBitSet(r24->succ[0], pred1->dom) && !Bv_IsBitSet(r24->succ[0], pred2->dom) && Bv_IsBitSet(r24->succ[1], pred2->dom) && !Bv_IsBitSet(r24->succ[1], pred1->dom)) break; if (Bv_IsBitSet(r24->succ[0], pred2->dom) && !Bv_IsBitSet(r24->succ[0], pred1->dom) && Bv_IsBitSet(r24->succ[1], pred1->dom) && !Bv_IsBitSet(r24->succ[1], pred2->dom)) break; } } if (i >= IRO_NumNodes) return; /*if ( (r30 = IRO_NodeTable[r24->succ[0]]) && r30->numpred == 1 && r30->first && r30->first->type == IROLinearLabel && r30->first->u.label.label == r24->last->u.label.label ) { goto ok; } else if ( (r30 = IRO_NodeTable[r24->succ[1]]) && r30->numpred == 1 && r30->first && r30->first->type == IROLinearLabel && r30->first->u.label.label == r24->last->u.label.label ) { goto ok; } else { return; }*/ /*if ( (!(r30 = IRO_NodeTable[r24->succ[0]]) || r30->numpred != 1 || !r30->first || r30->first->type != IROLinearLabel || r30->first->u.label.label != r24->last->u.label.label) && (!(r30 = IRO_NodeTable[r24->succ[1]]) || r30->numpred != 1 || !r30->first || r30->first->type != IROLinearLabel || r30->first->u.label.label != r24->last->u.label.label) ) return;*/ r30 = IRO_NodeTable[r24->succ[0]]; if ( r30 && r30->numpred == 1 && r30->first && r30->first->type == IROLinearLabel && r30->first->u.label.label == r24->last->u.label.label ) { (void)0; } else { r30 = IRO_NodeTable[r24->succ[1]]; if ( r30 && r30->numpred == 1 && r30->first && r30->first->type == IROLinearLabel && r30->first->u.label.label == r24->last->u.label.label ) { } else { return; } } ok: if (Bv_IsBitSet(r30->index, pred1->dom)) { left = pred2; right = pred1; } else { left = pred1; right = pred2; } leftAss = FindLastDiadicTopLevelAssignmentInFlowgraphNode(left); if ( !leftAss || leftAss->type != IROLinearOp2Arg || !leftAss->u.diadic.left || leftAss->u.diadic.left->type != IROLinearOp1Arg || leftAss->u.diadic.left->nodetype != EINDIRECT || !leftAss->u.diadic.left->u.monadic || leftAss->u.diadic.left->u.monadic->type != IROLinearOperand || !(r23 = leftAss->u.diadic.left->u.monadic->u.node) || !r23->rtype || !IS_TYPE_POINTER_ONLY(r23->rtype) || !r23->data.objref || is_volatile_object(r23->data.objref) || r23->data.objref->datatype != DLOCAL ) r23 = NULL; if (r23) { rightAss = FindLastDiadicTopLevelAssignmentInFlowgraphNode(right); if ( !rightAss || rightAss->type != IROLinearOp2Arg || !rightAss->u.diadic.left || rightAss->u.diadic.left->type != IROLinearOp1Arg || rightAss->u.diadic.left->nodetype != EINDIRECT || !rightAss->u.diadic.left->u.monadic || rightAss->u.diadic.left->u.monadic->type != IROLinearOperand || !rightAss->u.diadic.left->u.monadic->u.node || !rightAss->u.diadic.left->u.monadic->u.node->rtype || !IS_TYPE_POINTER_ONLY(rightAss->u.diadic.left->u.monadic->u.node->rtype) || rightAss->u.diadic.left->u.monadic->u.node->type != EOBJREF || rightAss->u.diadic.left->u.monadic->u.node->data.objref != r23->data.objref || rightAss->rtype != leftAss->rtype ) r23 = NULL; } if (r23) { if (!CheckThenOrElseBranch(r24->nextnode, left, leftAss, 0) || !CheckThenOrElseBranch(r30, right, rightAss, 0)) return; r19 = 0; r20 = 0; r18 = 0; r17 = 0; if (!r23->data.objref->varptr || !r23->data.objref->varptr->uses || !r23->data.objref->varptr->defs) { r23 = NULL; } else { r21 = NULL; r22 = NULL; for (def = r23->data.objref->varptr->defs; def && (!r22 || !r21); def = def->varnext) { if (def->x18 && def->linear == leftAss) r22 = def; else if (def->x18 && def->linear == rightAss) r21 = def; } if (!r22 || !r21) { r23 = NULL; } else { for (use = r23->data.objref->varptr->uses; r23 && use; use = use->varnext) { if (use->x1C) { r20++; if (Bv_IsBitSet(r22->index, use->x18) && Bv_IsBitSet(r21->index, use->x18)) { for (i = 0; r23 && i < use->x18->size; i++) { if (i != r22->index && i != r21->index && Bv_IsBitSet(i, use->x18)) r23 = NULL; } if (r23 && !Bv_IsBitSet(fnode->index, use->node->dom)) r23 = NULL; if (r23) { if (RewriteUse(use, r23, rightAss, 0)) r19++; else r23 = NULL; } if (r23 && !r17) r17 = HasSideEffectsBeforeUse(fnode, fnode, use->node, use->linear, 1); if (r23 && !r18 && (IRO_HasSideEffect(r24->last->u.label.x4) || IRO_HasSideEffect(leftAss->u.label.x4) || IRO_HasSideEffect(rightAss->u.label.x4))) r18 = 1; } else if (Bv_IsBitSet(r22->index, use->x18) || Bv_IsBitSet(r21->index, use->x18)) { r23 = NULL; } } } } } } if (!r23) return; compareType = r24->last->type == IROLinearIf; r27 = r24->last->u.label.x4; r13 = leftAss->u.label.x4; var_58 = rightAss->u.label.x4; var_60 = rightAss->rtype; memcpy(©1, r13, sizeof(IROLinear)); memcpy(©2, rightAss, sizeof(IROLinear)); r24->last->type = IROLinearNop; r24->last->expr = NULL; r30->first->type = IROLinearNop; r30->first->expr = NULL; fnode->first->type = IROLinearNop; fnode->first->expr = NULL; if (left->last->type == IROLinearGoto) { left->last->type = IROLinearNop; left->last->expr = NULL; } if (right->last->type == IROLinearGoto) { right->last->type = IROLinearNop; right->last->expr = NULL; } if (r23) { IRO_NopOut(leftAss->u.diadic.left); leftAss->type = IROLinearNop; leftAss->expr = NULL; } memcpy(rightAss, ©1, sizeof(IROLinear)); rightAss->type = IROLinearOp3Arg; rightAss->nodetype = ECOND; rightAss->index = copy2.index; rightAss->u.args3.a = r27; rightAss->rtype = var_60; rightAss->next = copy2.next; if (compareType) { rightAss->u.args3.b = var_58; rightAss->u.args3.c = r13; } else { rightAss->u.args3.b = r13; rightAss->u.args3.c = var_58; } rightAss->flags |= IROLF_Reffed; if (r19 == 1 && !r17 && !r18 && !r23->data.objref->varptr->xB) { for (use = r23->data.objref->varptr->uses; use; use = use->varnext) { if (use->x1C && Bv_IsBitSet(r22->index, use->x18) && Bv_IsBitSet(r21->index, use->x18)) { RewriteUse(use, r23, rightAss, 1); if ((r18 = (use->linear->flags & IROLF_4000) && IRO_HasSideEffect(r27))) { IROLinear *tmp; Object *obj; tmp = IRO_NewLinear(IROLinearOperand); memcpy(tmp, copy2.u.diadic.left->u.monadic, sizeof(IROLinear)); tmp->index = IRO_NumLinear++; tmp->rtype = r27->rtype; if (r20 == 1) { tmp->u.node->data.objref->type = r27->rtype; tmp->u.node->rtype = CDecl_NewPointerType(r27->rtype); } else { obj = create_temp_object(tmp->rtype); IRO_FindVar(obj, 1, 1); tmp->u.node = create_objectrefnode(obj); } IRO_PasteAfter(tmp, tmp, r27); tmp = IRO_NewLinear(IROLinearOp1Arg); memcpy(tmp, copy2.u.diadic.left, sizeof(IROLinear)); tmp->index = IRO_NumLinear++; tmp->u.monadic = r27->next; tmp->rtype = r27->rtype; IRO_PasteAfter(tmp, tmp, r27->next); tmp = IRO_NewLinear(IROLinearOp2Arg); memcpy(tmp, ©2, sizeof(IROLinear)); tmp->index = IRO_NumLinear++; tmp->u.diadic.right = r27; tmp->u.diadic.left = r27->next->next; tmp->rtype = r27->rtype; IRO_PasteAfter(tmp, tmp, r27->next->next); if (r20 != 1) { tmp = copy2.u.diadic.left->u.monadic; tmp->u.node = create_objectrefnode(obj); } rightAss->u.args3.a = copy2.u.diadic.left; rightAss->u.args3.a->rtype = r27->rtype; if (r20 == 1) { r21->linear = r27->next->next; if (Bv_IsBitSet(r21->index, right->x1A)) { Bv_ClearBit(r21->index, right->x1A); Bv_SetBit(r21->index, r24->x1A); } if (Bv_IsBitSet(r21->index, right->x1E)) { Bv_ClearBit(r21->index, right->x1E); Bv_SetBit(r21->index, r24->x1E); } if (Bv_IsBitSet(r21->index, right->x22)) { Bv_ClearBit(r21->index, right->x22); Bv_SetBit(r21->index, r24->x22); } } } } } if (!r18) { if (r20 == 1 && r23->data.objref->u.var.info) { r23->data.objref->u.var.info->usage = 0; r23->data.objref->u.var.info->used = 0; } r22->x18 = 0; IRO_NopOut(copy2.u.diadic.left); r21->x18 = 0; } } else { memcpy(©3, fnode->first, sizeof(IROLinear)); memcpy(fnode->first, ©2, sizeof(IROLinear)); fnode->first->index = copy3.index; fnode->first->u.diadic.right = rightAss; fnode->first->next = copy3.next; r22->x18 = 0; r21->linear = fnode->first; if (Bv_IsBitSet(r21->index, right->x1A)) { Bv_ClearBit(r21->index, right->x1A); Bv_SetBit(r21->index, fnode->x1A); } if (Bv_IsBitSet(r21->index, right->x1E)) { Bv_ClearBit(r21->index, right->x1E); Bv_SetBit(r21->index, fnode->x1E); } if (Bv_IsBitSet(r21->index, right->x22)) { Bv_ClearBit(r21->index, right->x22); Bv_SetBit(r21->index, fnode->x22); } } } static void RebuildPossibleReturnCondExpression(IRONode *fnode) { IRONode *succ1; IRONode *succ2; IROLinear *node1; IROLinear *node2; IROLinear *node3; IRONode *r27; Boolean isIf; Type *type; IROList list; if ( !fnode || fnode->numsucc != 2 || !fnode->last || (fnode->last->type != IROLinearIf && fnode->last->type != IROLinearIfNot) ) return; succ1 = IRO_NodeTable[fnode->succ[0]]; succ2 = IRO_NodeTable[fnode->succ[1]]; if ( !succ1 || !succ2 || succ1->numsucc != 0 || succ1->numpred != 1 || succ2->numsucc != 0 || succ2->numpred != 1 ) return; if (succ1->first && succ1->first->type == IROLinearLabel && succ1->first->u.label.label == fnode->last->u.label.label) { r27 = succ1; } else if (succ2->first && succ2->first->type == IROLinearLabel && succ2->first->u.label.label == fnode->last->u.label.label) { r27 = succ2; } else { return; } if (r27->numpred != 1) return; if (!CheckThenOrElseBranch(fnode->nextnode, fnode->nextnode, NULL, 1) || !CheckThenOrElseBranch(r27, r27, NULL, 1)) return; if ( !fnode->nextnode->last || fnode->nextnode->last->type != IROLinearReturn || !fnode->nextnode->last->u.monadic || !r27->last || r27->last->type != IROLinearReturn || !r27->last->u.monadic || !IRO_TypesEqual(fnode->nextnode->last->u.monadic->rtype, r27->last->u.monadic->rtype) ) return; isIf = fnode->last->type == IROLinearIf; node1 = fnode->last->u.diadic.right; node2 = fnode->nextnode->last->u.diadic.left; node3 = r27->last->u.diadic.left; type = node2->rtype; fnode->last->type = IROLinearNop; fnode->last->expr = NULL; r27->last->type = IROLinearNop; r27->last->expr = NULL; r27->first->type = IROLinearNop; r27->first->expr = NULL; if (IRO_IsIntConstant(node2) && IRO_IsIntConstant(node3) && ((IRO_IsConstantOne(node2) && IRO_IsConstantZero(node3)) || (IRO_IsConstantZero(node2) && IRO_IsConstantOne(node3)))) { if (!(node1->type == IROLinearOp1Arg && node1->nodetype == ELOGNOT && node1->rtype == type)) { IROLinear *tmp1; IROLinear *tmp2; tmp1 = IRO_NewLinear(IROLinearOp1Arg); memcpy(tmp1, node2, sizeof(IROLinear)); tmp1->type = IROLinearOp1Arg; tmp1->nodetype = ELOGNOT; tmp1->index = IRO_NumLinear++; tmp1->u.monadic = node1; tmp1->next = tmp2 = IRO_NewLinear(IROLinearOp1Arg); memcpy(tmp2, node2, sizeof(IROLinear)); tmp2->type = IROLinearOp1Arg; tmp2->nodetype = ELOGNOT; tmp2->index = IRO_NumLinear++; tmp2->u.monadic = tmp1; IRO_PasteAfter(tmp1, tmp2, node1); node1 = tmp2; } if ((IRO_IsConstantZero(node2) && !isIf) || (IRO_IsConstantOne(node2) && isIf)) { if (node1->type == IROLinearOp1Arg && node1->nodetype == ELOGNOT && node1->rtype == node1->u.monadic->rtype) { IROLinear *tmp = node1; node1 = node1->u.monadic; tmp->type = IROLinearNop; tmp->expr = NULL; } else { IROLinear *tmp = IRO_NewLinear(IROLinearOp1Arg); memcpy(tmp, node2, sizeof(IROLinear)); tmp->type = IROLinearOp1Arg; tmp->nodetype = ELOGNOT; tmp->index = IRO_NumLinear++; tmp->u.monadic = node1; IRO_PasteAfter(tmp, tmp, node1); node1 = tmp; } } node2->type = IROLinearNop; node2->expr = NULL; node3->type = IROLinearNop; node3->expr = NULL; fnode->nextnode->last->u.monadic = node1; } else { IROLinear *tmp1; IROLinear *tmp2; IRO_InitList(&list); tmp1 = IRO_DuplicateExpr(node3, &list); IRO_NopOut(node3); IRO_Paste(list.head, list.tail, fnode->nextnode->last); tmp2 = IRO_NewLinear(IROLinearOp3Arg); memcpy(tmp2, node2, sizeof(IROLinear)); tmp2->type = IROLinearOp3Arg; tmp2->nodetype = ECOND; tmp2->index = IRO_NumLinear++; tmp2->u.args3.a = node1; tmp2->rtype = type; IRO_Paste(tmp2, tmp2, fnode->nextnode->last); if (isIf) { tmp2->u.args3.b = tmp1; tmp2->u.args3.c = node2; } else { tmp2->u.args3.b = node2; tmp2->u.args3.c = tmp1; } fnode->nextnode->last->u.monadic = tmp2; } } static void RebuildCondExpressions(void) { IRONode *fnode; for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { if (fnode->numpred == 2) { if (fnode->first && fnode->first->type == IROLinearLabel) RebuildPossibleCondExpression(fnode); } else if (fnode->numsucc == 2) { if (fnode->last && (fnode->last->type == IROLinearIf || fnode->last->type == IROLinearIfNot)) RebuildPossibleReturnCondExpression(fnode); } } IRO_CheckForUserBreak(); } static Boolean IsLogicalExpressionAssign(IROLinear *nd) { IROLinear *right; IROLinear *left; return ( nd->type == IROLinearOp2Arg && nd->nodetype == EASS && (left = nd->u.diadic.left) && (right = nd->u.diadic.right) && right->type == IROLinearOperand && right->u.node && right->u.node->type == EINTCONST && (CInt64_Equal(right->u.node->data.intval, cint64_one) || CInt64_Equal(right->u.node->data.intval, cint64_zero)) && left->type == IROLinearOp1Arg && left->nodetype == EINDIRECT && left->u.monadic && IS_TYPE_POINTER_ONLY(left->u.monadic->rtype) && left->u.monadic->type == IROLinearOperand && left->u.monadic->u.node && left->u.monadic->u.node->type == EOBJREF && left->u.monadic->u.node->data.objref && left->u.monadic->u.node->data.objref->datatype == DLOCAL); } static Boolean IsPossibleLogicalExpressionStart(IRONode *fnode, IROLinear *nd) { return fnode->numsucc == 2 && fnode->last && (fnode->last->type == IROLinearIf || fnode->last->type == IROLinearIfNot) && IsLogicalExpressionAssign(nd); } static Boolean CheckForTopLevelExpressions(IRONode *fnode1, IRONode *fnode2, IRONode *fnode3, IROLinear *nd1, IROLinear *nd2, Boolean flag) { IRONode *fnode; IROLinear *nd; UInt16 i; if (fnode1 != fnode3) { if (!Bv_IsBitSet(fnode2->index, fnode1->dom)) return 0; if (flag) { for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) fnode->x3C = 0; } else if (fnode1->x3C) { return 1; } fnode1->x3C = 1; for (i = 0; i < fnode1->numsucc; i++) { fnode = IRO_NodeTable[fnode1->succ[i]]; if (!CheckForTopLevelExpressions(fnode, fnode2, fnode3, fnode->first, nd2, 0)) return 0; } } for (nd = nd1; nd && nd != fnode1->last->next; nd = nd->next) { if (nd == nd2) return 1; if (nd->type != IROLinearNop && nd->type != IROLinearLabel && !(nd->flags & IROLF_Reffed)) return 0; } return 1; } static void AddNodeAndSuccessorsRecursively(IRONodes *nodes, IRONode *fnode1, IRONode *fnode2) { UInt16 i; if (fnode1 && !fnode1->x3C) { fnode1->x3C = 1; IROFlowgraph_sub_4C3880(nodes, fnode1->index); if (fnode1 != fnode2) { for (i = 0; i < fnode1->numsucc; i++) AddNodeAndSuccessorsRecursively(nodes, IRO_NodeTable[fnode1->succ[i]], fnode2); } } } static Boolean RebuildPossibleLogicalExpression(IRONode *fnode, IROLinear *nd) { IROUse *use; IROLinear *nd2; IROLinear *left; IROLinear *right; IRONode *r25; IRONode *r24; ENode *objnode; IRODef *def1; IRODef *def2; UInt32 useCount; UInt32 rewrittenUseCount; Boolean sideEffectFlag; IROLinearType compareType; CLabel *somelab; IRONode *var_68; IRONode *var_6C; CInt64 compareVal; Boolean killedFlag; BitVector *bv1; BitVector *bv2; IROLinear *father; IROLinear *iter; IRODef *def; UInt32 i; IROLinear *newlin; objnode = nd->u.diadic.left->u.monadic->u.node; if (!objnode->data.objref->varptr) return 0; if (CInt64_Equal(nd->u.diadic.right->u.node->data.intval, cint64_zero)) { compareType = IROLinearIfNot; compareVal = cint64_one; } else { compareType = IROLinearIf; compareVal = cint64_zero; } var_68 = NULL; def1 = NULL; for (def = objnode->data.objref->varptr->defs; def && !def1; def = def->varnext) { if (def->x18 && def->linear == nd) def1 = def; } if (def1) { for (use = objnode->data.objref->varptr->uses; use; use = use->varnext) { if (use->x1C == 2 && Bv_IsBitSet(def1->index, use->x18)) { if (!var_68) { var_68 = use->node; } else if (Bv_IsBitSet(use->node->index, var_68->dom)) { var_68 = use->node; } } } if (var_68) { for (use = objnode->data.objref->varptr->uses; use; use = use->varnext) { if (use->node != var_68 && use->x1C == 2 && Bv_IsBitSet(def1->index, use->x18) && !Bv_IsBitSet(var_68->index, use->node->dom)) { var_68 = NULL; break; } } } } if ( !var_68 || !var_68->first || var_68->first->type != IROLinearLabel || !(somelab = var_68->first->u.label.label) || var_68->numpred != 3 ) return 0; r25 = IRO_NodeTable[var_68->pred[0]]; if (Bv_IsBitSet(IRO_NodeTable[var_68->pred[1]]->index, r25->dom)) { r25 = IRO_NodeTable[var_68->pred[1]]; } else if (!Bv_IsBitSet(r25->index, IRO_NodeTable[var_68->pred[1]]->dom)) { return 0; } if (Bv_IsBitSet(IRO_NodeTable[var_68->pred[2]]->index, r25->dom)) { r25 = IRO_NodeTable[var_68->pred[2]]; } else if (!Bv_IsBitSet(r25->index, IRO_NodeTable[var_68->pred[2]]->dom)) { return 0; } if ( !r25 || !(left = r25->last) || left->type != compareType || left->u.label.label != somelab ) return 0; if ( !FindFlowgraphNodeThatStartsWithLabel(left->u.label.label, &var_68, &var_6C) || !var_6C || var_6C->numpred != 1 || !(r24 = IRO_NodeTable[var_6C->pred[0]]) || !(right = r24->last) || right->type != compareType || right->u.label.label != left->u.label.label || !(nd2 = FindLastDiadicTopLevelAssignmentInFlowgraphNode(var_6C)) || !IsLogicalExpressionAssign(nd2) || nd2->u.diadic.left->u.monadic->u.node->data.objref != objnode->data.objref || !CInt64_Equal(compareVal, nd2->u.diadic.right->u.node->data.intval) || nd2->rtype != nd->rtype ) return 0; if ( !CheckForTopLevelExpressions(fnode, fnode, r25, nd->next, left, 1) || !CheckForTopLevelExpressions(r25->nextnode, r25->nextnode, r24, r25->nextnode->first, right, 1) || !CheckForTopLevelExpressions(r24->nextnode, r24->nextnode, var_6C, right->next, nd2, 1) || !CheckForTopLevelExpressions(var_6C, var_6C, var_6C, nd2->next, var_68->first, 1) ) return 0; rewrittenUseCount = 0; useCount = 0; killedFlag = 0; sideEffectFlag = 0; if (!objnode->data.objref->varptr || !(objnode->data.objref->varptr->uses) || !(objnode->data.objref->varptr->defs)) { objnode = NULL; } else { def1 = def2 = NULL; for (def = objnode->data.objref->varptr->defs; def && (!def1 || !def2); def = def->varnext) { if (def->x18 && def->linear == nd) def1 = def; else if (def->x18 && def->linear == nd2) def2 = def; } if (!def1 || !def2) { objnode = NULL; } else { for (use = objnode->data.objref->varptr->uses; objnode && use; use = use->varnext) { if (use->x1C) { useCount++; if (Bv_IsBitSet(def1->index, use->x18) && Bv_IsBitSet(def2->index, use->x18)) { for (i = 0; objnode && i < use->x18->size; i++) { if (i != def1->index && i != def2->index && Bv_IsBitSet(i, use->x18)) objnode = NULL; } if (objnode && !Bv_IsBitSet(var_68->index, use->node->dom)) objnode = NULL; if (objnode) { if (RewriteUse(use, objnode, nd2, 0)) rewrittenUseCount++; else objnode = NULL; } if (objnode) { if (!sideEffectFlag) sideEffectFlag = HasSideEffectsBeforeUse(var_68, var_68, use->node, use->linear, 1); if (!killedFlag && (IRO_HasSideEffect(left->u.label.x4) || IRO_HasSideEffect(right->u.label.x4))) { iter = use->linear; if ((father = IRO_LocateFather(use->linear))) { Bv_AllocVector(&bv1, IRO_NumVars + 1); Bv_AllocVector(&bv2, IRO_NumVars + 1); Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1); IRO_WalkTree(left->u.label.x4, GetExprKills); IRO_WalkTree(right->u.label.x4, GetExprKills); Bv_Or(IRO_VarKills, bv1); while (father && !killedFlag) { CheckUnorderedRegionsForSideEffectsAndUses(father, iter, bv1, bv2, &killedFlag); iter = father; father = IRO_LocateFather(father); } } if (!killedFlag) killedFlag = UsesAKilledVarBeforeUse(var_68, var_68, use->node, use->linear, bv1, 1); } } } else if (Bv_IsBitSet(def1->index, use->x18) || Bv_IsBitSet(def2->index, use->x18)) objnode = NULL; } } } } if (!objnode) return 0; left->type = right->type = IROLinearNop; left->expr = right->expr = NULL; IRO_NopOut(nd); newlin = IRO_NewLinear(IROLinearOp2Arg); memcpy(newlin, nd2, sizeof(IROLinear)); newlin->nodetype = (compareType == IROLinearIf) ? ELOR : ELAND; newlin->index = IRO_NumLinear++; newlin->u.diadic.left = left->u.label.x4; newlin->u.diadic.right = right->u.label.x4; newlin->flags |= IROLF_Reffed; IRO_Paste(newlin, newlin, nd2); if (rewrittenUseCount == 1 && !sideEffectFlag && !killedFlag && !objnode->data.objref->varptr->xB) { for (use = objnode->data.objref->varptr->uses; use; use = use->varnext) { if (use->x1C && Bv_IsBitSet(def1->index, use->x18) && Bv_IsBitSet(def2->index, use->x18)) RewriteUse(use, objnode, newlin, 1); } if (useCount == 1 && objnode->data.objref->u.var.info) { objnode->data.objref->u.var.info->usage = 0; objnode->data.objref->u.var.info->used = 0; } IRO_NopOut(nd2); def1->x18 = 0; def2->x18 = 0; } else { IRO_NopOut(nd2->u.label.x4); nd2->u.label.x4 = newlin; def1->x18 = 0; } if (r24->numpred == 1 && IRO_NodeTable[r24->pred[0]] == r25 && IRO_MergeFlowGraphNodes(r25, r24)) r24 = r25; if (var_6C->numpred == 1 && IRO_NodeTable[var_6C->pred[0]] == r24 && IRO_MergeFlowGraphNodes(r24, var_6C)) var_6C = r24; if (var_68->numpred == 1 && r24 == r25 && var_6C == r24) IRO_MergeFlowGraphNodes(var_6C, var_68); return 1; } static void RebuildLogicalExpressions(void) { IRONode *fnode; IROLinear *nd; Boolean flag; flag = 1; while (flag) { flag = 0; for (fnode = IRO_FirstNode; fnode && fnode->last; fnode = fnode->nextnode) { for (nd = fnode->first; nd && nd != fnode->last->next; nd = nd->next) { if (IsPossibleLogicalExpressionStart(fnode, nd) && RebuildPossibleLogicalExpression(fnode, nd)) flag = 1; } } } IRO_CheckForUserBreak(); } static Boolean IsPossibleCondAssStart(IRONode *fnode) { return (fnode->numsucc == 2) && fnode->last && (fnode->last->type == IROLinearIf || fnode->last->type == IROLinearIfNot); } static Type *logicalType(void) { if (copts.cplusplus && copts.booltruefalse) return TYPE(&stbool); else return TYPE(&stsignedint); } static Boolean GeneratePossibleCondAss(IRONode *fnode) { IROLinear *r31; IRONode *node2; IRONode *r29; Boolean r28; IRONode *node1; IROLinear *r24; Boolean r23; IROLinear *r19; Boolean r18; IROLinear *r20; Boolean r19flag; IROLinear *r18nd; IROLinear *ass; IROLinear *cond; IROLinear *r16; IROLinear *r15; BitVector *saveVarKills; IROList list; Object *obj; IROLinear *r14; if (!fnode || fnode->numsucc != 2 || !fnode->last || (fnode->last->type != IROLinearIf && fnode->last->type != IROLinearIfNot)) return 0; if (IRO_NodeTable[fnode->succ[0]] && IRO_NodeTable[fnode->succ[0]]->first && IRO_NodeTable[fnode->succ[0]]->first->type == IROLinearLabel && IRO_NodeTable[fnode->succ[0]]->first->u.label.label == fnode->last->u.label.label) { node1 = IRO_NodeTable[fnode->succ[0]]; node2 = IRO_NodeTable[fnode->succ[1]]; } else { node1 = IRO_NodeTable[fnode->succ[1]]; if (node1 && node1->first && node1->first->type == IROLinearLabel && node1->first->u.label.label == fnode->last->u.label.label) { node2 = IRO_NodeTable[fnode->succ[0]]; } else { return 0; } } if (!node2 || node2->numpred != 1 || node2->numsucc != 1 || node2->last->next != node1->first) return 0; if (IRO_NodeTable[node2->succ[0]] == node1 && Bv_IsBitSet(fnode->index, node1->dom)) { r28 = 0; } else if ( node1->numpred == 1 && node1->numsucc == 1 && node2->succ[0] == node1->succ[0] && (r29 = IRO_NodeTable[node2->succ[0]]) && Bv_IsBitSet(fnode->index, r29->dom) && node1->last->next == r29->first ) { r28 = 1; } else { return 0; } r24 = NULL; if (node2->last) { for (r19 = node2->first; r19 && r19 != node2->last->next; r19 = r19->next) { if (IRO_IsAssignment(r19) && !(r19->flags & IROLF_Reffed) && !r24) { r24 = r19; } else if (r19->type != IROLinearNop && r19->type != IROLinearLabel && r19->type != IROLinearGoto && !(r19->flags & IROLF_Reffed)) { return 0; } } } if ( !r24 || (r24->nodetype != EASS && !IRO_TransformSelfAssignmentToAssignment(r24)) || !r24->u.diadic.left || r24->u.diadic.left->type != IROLinearOp1Arg || r24->u.diadic.left->nodetype != EINDIRECT || !r24->u.diadic.left->u.monadic || r24->u.diadic.left->u.monadic->type != IROLinearOperand || !r24->u.diadic.left->u.monadic->u.node || !r24->u.diadic.left->u.monadic->u.node->rtype || !IS_TYPE_POINTER_ONLY(r24->u.diadic.left->u.monadic->u.node->rtype) || !r24->u.diadic.left->u.monadic->u.node->data.monadic ) return 0; if (r28) { r31 = NULL; if (node1->last) { for (r19 = node1->first; r19 && r19 != node1->last->next; r19 = r19->next) { if (IRO_IsAssignment(r19) && !(r19->flags & IROLF_Reffed) && !r31) { r31 = r19; } else if (r19->type != IROLinearNop && r19->type != IROLinearLabel && r19->type != IROLinearGoto && !(r19->flags & IROLF_Reffed)) { return 0; } } } if ( !r31 || (r31->nodetype != EASS && !IRO_TransformSelfAssignmentToAssignment(r31)) || !r31->u.diadic.left || r31->u.diadic.left->type != IROLinearOp1Arg || r31->u.diadic.left->nodetype != EINDIRECT || !r31->u.diadic.left->u.monadic || r31->u.diadic.left->u.monadic->type != IROLinearOperand || !r31->u.diadic.left->u.monadic->u.node || !r31->u.diadic.left->u.monadic->u.node->rtype || !IS_TYPE_POINTER_ONLY(r31->u.diadic.left->u.monadic->u.node->rtype) || !r31->u.diadic.left->u.monadic->u.node->data.monadic ) return 0; r18 = IRO_ExprsSame(r24->u.diadic.left, r31->u.diadic.left); } r23 = fnode->last->type == IROLinearIf; r20 = fnode->last->u.diadic.right; r19flag = 0; if (r28 && copts.commonsubs && IRO_IsSubableExpression(r20)) r19flag = 1; if (r19flag) { IRO_FindDepends(r20); r19flag = !IRO_NotSubable; } if (r28) { if (r18) { r19flag = 0; } else if (IRO_HasSideEffect(r20)) { r19flag = 1; } else { Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1); IRO_WalkTree(r20, GetExprUses); saveVarKills = IRO_VarKills; Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1); IRO_WalkTree(r20, GetExprKills); if (Bv_BitsInCommon(IRO_VarKills, saveVarKills)) r19flag = 1; } if (r19flag && !copts.commonsubs) return 0; } if (r19flag) { IRO_InitList(&list); obj = create_temp_object(r20->rtype); IRO_FindVar(obj, 1, 1); ass = IRO_NewLinear(IROLinearOp2Arg); ass->u.diadic.left = IRO_TempReference(obj, &list); ass->rtype = r20->rtype; ass->nodetype = EASS; ass->index = ++IRO_NumLinear; ass->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned; ass->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned; ass->u.diadic.right = r20; IRO_AddToList(ass, &list); IRO_PasteAfter(list.head, list.tail, r20); } r16 = r24->u.diadic.left; r15 = r24->u.diadic.right; fnode->last->type = IROLinearNop; fnode->last->expr = NULL; if (node2->last->type == IROLinearGoto) { node2->last->type = IROLinearNop; node2->last->expr = NULL; } if (r28 || node1->numpred == 2) { node1->first->type = IROLinearNop; node1->first->expr = NULL; } if (r28 && r18) { if (node1->last->type == IROLinearGoto) { node1->last->type = IROLinearNop; node1->last->expr = NULL; } if (r29->numpred == 2) { r29->first->type = IROLinearNop; r29->first->expr = NULL; } cond = IRO_NewLinear(IROLinearOp3Arg); memcpy(cond, r24, sizeof(IROLinear)); cond->type = IROLinearOp3Arg; cond->nodetype = ECOND; cond->index = ++IRO_NumLinear; cond->rtype = r16->rtype; cond->flags |= IROLF_Reffed; if (r19flag) { IRO_InitList(&list); r14 = IRO_TempReference(obj, &list); IRO_Paste(list.head, list.tail, r31); } else { r14 = r20; } cond->u.args3.a = r14; if (r23) { cond->u.args3.b = r31->u.diadic.right; cond->u.args3.c = r15; } else { cond->u.args3.b = r15; cond->u.args3.c = r31->u.diadic.right; } r24->type = IROLinearNop; r24->expr = NULL; IRO_NopOut(r24->u.diadic.left); IRO_Paste(cond, cond, r31); r31->u.diadic.right = cond; } else { r24->type = IROLinearOp3Arg; r24->nodetype = ECONDASS; if (r19flag) { IRO_InitList(&list); r20 = IRO_TempReference(obj, &list); IRO_Paste(list.head, list.tail, r24); } cond = r20; if (r23) { r18nd = IRO_NewLinear(IROLinearOp1Arg); memcpy(r18nd, r20, sizeof(IROLinear)); r18nd->type = IROLinearOp1Arg; r18nd->nodetype = ELOGNOT; r18nd->index = ++IRO_NumLinear; r18nd->rtype = logicalType(); r18nd->u.monadic = r20; r18nd->flags |= IROLF_Reffed; IRO_Paste(r18nd, r18nd, r24); r20 = r18nd; } r24->u.args3.a = r20; r24->u.args3.b = r16; r24->u.args3.c = r15; if (r28) { r15 = r31->u.diadic.left; r16 = r31->u.diadic.right; if (node1->last->type == IROLinearGoto) { node1->last->type = IROLinearNop; node1->last->expr = NULL; } if (r29->numpred == 2) { r29->first->type = IROLinearNop; r29->first->expr = NULL; } r31->type = IROLinearOp3Arg; r31->nodetype = ECONDASS; if (r19flag) { IRO_InitList(&list); cond = IRO_TempReference(obj, &list); IRO_Paste(list.head, list.tail, r31); } else { IRO_InitList(&list); cond = IRO_DuplicateExpr(cond, &list); IRO_Paste(list.head, list.tail, r31); } if (!r23) { r14 = IRO_NewLinear(IROLinearOp1Arg); memcpy(r14, cond, sizeof(IROLinear)); r14->type = IROLinearOp1Arg; r14->nodetype = ELOGNOT; r14->index = ++IRO_NumLinear; r14->rtype = logicalType(); r14->u.monadic = cond; r14->flags |= IROLF_Reffed; IRO_Paste(r14, r14, r31); cond = r14; } r31->u.args3.a = cond; r31->u.args3.b = r15; r31->u.args3.c = r16; } } if (IRO_MergeFlowGraphNodes(fnode, node2)) node2 = fnode; if ((r28 || node1->numpred == 1) && IRO_MergeFlowGraphNodes(node2, node1)) node1 = node2; if (r28 && r29->numpred == 1) IRO_MergeFlowGraphNodes(node1, r29); return 1; } static void GenerateCondAssignments(void) { IRONode *fnode; fnode = IRO_FirstNode; while (fnode && fnode->last) { if (IsPossibleCondAssStart(fnode)) { if (!GeneratePossibleCondAss(fnode)) fnode = fnode->nextnode; } else { fnode = fnode->nextnode; } } IRO_CheckForUserBreak(); } void IRO_RegenerateExpressions(void) { IRO_UpdateFlagsOnInts(); IRO_ComputeSuccPred(); IRO_ComputeDom(); IRO_UseDef(0, 0); if (copts.optimizationlevel > 0) { IRO_Dump("Rebuilding ELORs and ELANDs\n"); RebuildLogicalExpressions(); IRO_DumpAfterPhase("RebuildLogicalExpressions", 0); } if (copts.optimizationlevel > 0) { IRO_Dump("Rebuilding ECONDs\n"); RebuildCondExpressions(); IRO_DumpAfterPhase("RebuildCondExpressions", 0); } if (copts.optimizationlevel > 0) { IRO_Dump("Generating ECONDASSes\n"); GenerateCondAssignments(); IRO_DumpAfterPhase("GenerateCondAssignments", 0); } }