#include "compiler/IROUseDef.h" #include "compiler/IRODump.h" #include "compiler/IROVars.h" #include "compiler/IroFlowgraph.h" #include "compiler/IroLinearForm.h" #include "compiler/IroMalloc.h" #include "compiler/IroPointerAnalysis.h" #include "compiler/IroTransform.h" #include "compiler/IroUtil.h" #include "compiler/CompilerTools.h" #include "compiler/CError.h" #include "compiler/CFunc.h" #include "compiler/CInt64.h" #include "compiler/CMachine.h" #include "compiler/CParser.h" #include "compiler/objects.h" #include "compiler/types.h" #include "compiler/InlineAsm.h" #include "compiler/InlineAsmPPC.h" ENodeType IRO_NonAssignmentOp[MAXEXPR]; typedef CInt64 (*AssignmentFoldingFunc)(CInt64, CInt64); static AssignmentFoldingFunc AssignmentFoldingFunction[MAXEXPR]; static SInt32 NumDefs; static IRODef *FirstDef; static IRODef *LastDef; static SInt32 NumUses; static BitVector *Reaches; static BitVector *MightReachAnyUse; static BitVector *alldefs; static BitVector *alluses; static BitVector *defset; static BitVector *useset; IROUse *IRO_FirstVarUse; IROUse *IRO_LastVarUse; // forward decls static void AddDefToRange(IRODef *def); static void MakeDef(VarRecord *var, IROLinear *linear, IRONode *node, Boolean flag) { IRODef *def = oalloc(sizeof(IRODef)); def->index = NumDefs++; def->node = node; def->linear = linear; def->var = var; def->globalnext = NULL; def->x18 = 0; def->x1A = Inline_IsObjectData(var->object); def->x1B = var->xB; def->x1C = flag; def->x1D = 0; if (FirstDef) LastDef->globalnext = def; else FirstDef = def; LastDef = def; def->varnext = var->defs; var->defs = def; } static void MakeUse(VarRecord *var, IROLinear *linear, IRONode *node) { IROUse *use = oalloc(sizeof(IROUse)); use->index = NumUses++; use->node = node; use->linear = linear; use->var = var; use->globalnext = NULL; use->x1C = 0; if (IRO_FirstVarUse) IRO_LastVarUse->globalnext = use; else IRO_FirstVarUse = use; IRO_LastVarUse = use; use->varnext = var->uses; var->uses = use; } static void FindDefsAndUses(void) { VarRecord *var; IROLinear *linear; IRONode *node; NumDefs = 0; NumUses = 0; IRO_FirstVarUse = NULL; FirstDef = NULL; for (var = IRO_FirstVar; var; var = var->next) { var->defs = NULL; var->uses = NULL; var->xC = 0; } for (node = IRO_FirstNode; node; node = node->nextnode) { for (linear = node->first; linear; linear = linear->next) { if (IS_LINEAR_ENODE(linear, EOBJREF)) { Object *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))) MakeUse(var, linear, node); } } if (IRO_IsAssignment(linear) && (var = IRO_FindAssigned(linear))) { MakeDef( var, linear, node, (linear->rtype->size == var->object->type->size) && !IRO_IsBitField ); } if (linear->type == IROLinearAsm) { IAEffects effects; int i; CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects); for (i = 0; i < effects.numoperands; i++) { var = IRO_FindVar(effects.operands[i].object, 0, 1); switch (effects.operands[i].type) { case IAEffect_0: MakeUse(var, linear, node); break; case IAEffect_1: MakeDef( var, linear, node, (effects.operands[i].offset == 0) && (effects.operands[i].size == var->object->type->size) ); break; case IAEffect_2: MakeDef(var, linear, node, 0); break; case IAEffect_4: MakeUse(var, linear, node); MakeDef( var, linear, node, (effects.operands[i].offset == 0) && (effects.operands[i].size == var->object->type->size) ); break; } } } if (linear == node->last) break; } } for (var = IRO_FirstVar; var; var = var->next) MakeDef(var, NULL, NULL, 1); } static void MarkUses(Object *obj) { VarRecord *var; IRODef *def; if ((var = IRO_FindVar(obj, 0, 1))) { for (def = var->defs; def; def = def->varnext) { if (Bv_IsBitSet(def->index, Reaches)) { Bv_SetBit(def->index, MightReachAnyUse); def->x18++; } } var->xC = 1; } } static Boolean IsIncOrDec(IROLinear *linear) { switch (linear->type) { case IROLinearOp1Arg: if (linear->nodetype == EPOSTINC || linear->nodetype == EPOSTDEC || linear->nodetype == EPREINC || linear->nodetype == EPREDEC) { if (!(linear->u.monadic->flags & IROLF_BitfieldIndirect)) return 1; } break; case IROLinearOp2Arg: if (linear->nodetype == EADDASS || linear->nodetype == ESUBASS) { if (IRO_IsIntConstant(linear->u.diadic.right) && !(linear->u.diadic.left->flags & IROLF_BitfieldIndirect)) return 1; } break; } return 0; } static Boolean IsOtherSelfAssignment(IROLinear *linear) { switch (linear->type) { case IROLinearOp2Arg: switch (linear->nodetype) { case EMULASS: case EDIVASS: case ESHLASS: case ESHRASS: case EANDASS: case EXORASS: case EORASS: if (IRO_IsIntConstant(linear->u.diadic.right)) return 1; break; } break; } return 0; } CInt64 IRO_GetSelfAssignmentVal(IROLinear *linear) { CInt64 result; if (linear->type == IROLinearOp1Arg) { switch (linear->nodetype) { case EPOSTINC: case EPREINC: CInt64_SetLong(&result, 1); break; case EPOSTDEC: case EPREDEC: CInt64_SetLong(&result, -1); break; default: CError_FATAL(445); } if (IS_TYPE_POINTER_ONLY(linear->rtype)) { CInt64 mul; CInt64_SetLong(&mul, TPTR_TARGET(linear->rtype)->size); result = CInt64_Mul(result, mul); } } else if (linear->type == IROLinearOp2Arg) { switch (linear->nodetype) { case EMULASS: case EDIVASS: case EMODASS: case EADDASS: case ESHLASS: case ESHRASS: case EANDASS: case EXORASS: case EORASS: result = linear->u.diadic.right->u.node->data.intval; break; case ESUBASS: result = linear->u.diadic.right->u.node->data.intval; result = CInt64_Neg(result); break; default: CError_FATAL(491); } } else { CError_FATAL(496); } return result; } static void UpdateUse(IROLinear *linear, CInt64 val, Type *type) { IROLinear *father; IROLinear *repl; IROLinear *newdiadic; if ((father = IRO_LocateFather(linear))) { switch (father->type) { case IROLinearOp1Arg: switch (father->nodetype) { case EPOSTINC: case EPOSTDEC: case EPREINC: case EPREDEC: val = CInt64_Add(val, IRO_GetSelfAssignmentVal(father)); father->nodetype = EADDASS; father->type = IROLinearOp2Arg; repl = IRO_NewIntConst(val, type); father->u.diadic.right = repl; IRO_PasteAfter(repl, repl, linear); return; } break; case IROLinearOp2Arg: if (IRO_IsIntConstant(father->u.diadic.right)) { switch (father->nodetype) { case EADD: case EADDASS: father->u.diadic.right->u.node->data.intval = CInt64_Add( father->u.diadic.right->u.node->data.intval, val); return; case ESUB: case ESUBASS: father->u.diadic.right->u.node->data.intval = CInt64_Sub( father->u.diadic.right->u.node->data.intval, val); return; } } break; } } repl = IRO_NewIntConst(val, type); newdiadic = IRO_NewLinear(IROLinearOp2Arg); newdiadic->index = ++IRO_NumLinear; newdiadic->nodetype = EADD; newdiadic->u.diadic.left = linear; newdiadic->u.diadic.right = repl; newdiadic->rtype = linear->rtype; repl->next = newdiadic; IRO_LocateFather_Cut_And_Paste_Without_Nopping(linear, newdiadic); IRO_PasteAfter(repl, newdiadic, linear); } void IRO_InitializeNonAssignmentOpArray(void) { int i; for (i = 0; i < MAXEXPR; i++) IRO_NonAssignmentOp[i] = MAXEXPR; IRO_NonAssignmentOp[EPOSTINC] = MAXEXPR; IRO_NonAssignmentOp[EPOSTDEC] = MAXEXPR; IRO_NonAssignmentOp[EPREINC] = MAXEXPR; IRO_NonAssignmentOp[EPREDEC] = MAXEXPR; IRO_NonAssignmentOp[EINDIRECT] = MAXEXPR; IRO_NonAssignmentOp[EMONMIN] = MAXEXPR; IRO_NonAssignmentOp[EBINNOT] = MAXEXPR; IRO_NonAssignmentOp[ELOGNOT] = MAXEXPR; IRO_NonAssignmentOp[EFORCELOAD] = MAXEXPR; IRO_NonAssignmentOp[EMUL] = MAXEXPR; IRO_NonAssignmentOp[EMULV] = MAXEXPR; IRO_NonAssignmentOp[EDIV] = MAXEXPR; IRO_NonAssignmentOp[EMODULO] = MAXEXPR; IRO_NonAssignmentOp[EADDV] = MAXEXPR; IRO_NonAssignmentOp[ESUBV] = MAXEXPR; IRO_NonAssignmentOp[EADD] = MAXEXPR; IRO_NonAssignmentOp[ESUB] = MAXEXPR; IRO_NonAssignmentOp[ESHL] = MAXEXPR; IRO_NonAssignmentOp[ESHR] = MAXEXPR; IRO_NonAssignmentOp[ELESS] = MAXEXPR; IRO_NonAssignmentOp[EGREATER] = MAXEXPR; IRO_NonAssignmentOp[ELESSEQU] = MAXEXPR; IRO_NonAssignmentOp[EGREATEREQU] = MAXEXPR; IRO_NonAssignmentOp[EEQU] = MAXEXPR; IRO_NonAssignmentOp[ENOTEQU] = MAXEXPR; IRO_NonAssignmentOp[EAND] = MAXEXPR; IRO_NonAssignmentOp[EXOR] = MAXEXPR; IRO_NonAssignmentOp[EOR] = MAXEXPR; IRO_NonAssignmentOp[ELAND] = MAXEXPR; IRO_NonAssignmentOp[ELOR] = MAXEXPR; IRO_NonAssignmentOp[EASS] = MAXEXPR; IRO_NonAssignmentOp[EMULASS] = EMUL; IRO_NonAssignmentOp[EDIVASS] = EDIV; IRO_NonAssignmentOp[EMODASS] = EMODULO; IRO_NonAssignmentOp[EADDASS] = EADD; IRO_NonAssignmentOp[ESUBASS] = ESUB; IRO_NonAssignmentOp[ESHLASS] = ESHL; IRO_NonAssignmentOp[ESHRASS] = ESHR; IRO_NonAssignmentOp[EANDASS] = EAND; IRO_NonAssignmentOp[EXORASS] = EXOR; IRO_NonAssignmentOp[EORASS] = EOR; IRO_NonAssignmentOp[ECOMMA] = MAXEXPR; IRO_NonAssignmentOp[EPMODULO] = MAXEXPR; IRO_NonAssignmentOp[EROTL] = MAXEXPR; IRO_NonAssignmentOp[EROTR] = MAXEXPR; IRO_NonAssignmentOp[EBCLR] = MAXEXPR; IRO_NonAssignmentOp[EBTST] = MAXEXPR; IRO_NonAssignmentOp[EBSET] = MAXEXPR; IRO_NonAssignmentOp[ETYPCON] = MAXEXPR; IRO_NonAssignmentOp[EBITFIELD] = MAXEXPR; IRO_NonAssignmentOp[EINTCONST] = MAXEXPR; IRO_NonAssignmentOp[EFLOATCONST] = MAXEXPR; IRO_NonAssignmentOp[ESTRINGCONST] = MAXEXPR; IRO_NonAssignmentOp[ECOND] = MAXEXPR; IRO_NonAssignmentOp[EFUNCCALL] = MAXEXPR; IRO_NonAssignmentOp[EFUNCCALLP] = MAXEXPR; IRO_NonAssignmentOp[EOBJREF] = MAXEXPR; IRO_NonAssignmentOp[EMFPOINTER] = MAXEXPR; IRO_NonAssignmentOp[ENULLCHECK] = MAXEXPR; IRO_NonAssignmentOp[EPRECOMP] = MAXEXPR; IRO_NonAssignmentOp[ETEMP] = MAXEXPR; IRO_NonAssignmentOp[EARGOBJ] = MAXEXPR; IRO_NonAssignmentOp[ELOCOBJ] = MAXEXPR; IRO_NonAssignmentOp[ELABEL] = MAXEXPR; IRO_NonAssignmentOp[ESETCONST] = MAXEXPR; IRO_NonAssignmentOp[ENEWEXCEPTION] = MAXEXPR; IRO_NonAssignmentOp[ENEWEXCEPTIONARRAY] = MAXEXPR; IRO_NonAssignmentOp[EOBJLIST] = MAXEXPR; IRO_NonAssignmentOp[EMEMBER] = MAXEXPR; IRO_NonAssignmentOp[ETEMPLDEP] = MAXEXPR; IRO_NonAssignmentOp[EINSTRUCTION] = MAXEXPR; IRO_NonAssignmentOp[EDEFINE] = MAXEXPR; IRO_NonAssignmentOp[EREUSE] = MAXEXPR; IRO_NonAssignmentOp[EASSBLK] = MAXEXPR; IRO_NonAssignmentOp[EVECTOR128CONST] = MAXEXPR; IRO_NonAssignmentOp[ECONDASS] = MAXEXPR; } void IRO_InitializeAssignmentFoldingFunctionArray(void) { int i; for (i = 0; i < MAXEXPR; i++) AssignmentFoldingFunction[i] = NULL; AssignmentFoldingFunction[EPOSTINC] = NULL; AssignmentFoldingFunction[EPOSTDEC] = NULL; AssignmentFoldingFunction[EPREINC] = NULL; AssignmentFoldingFunction[EPREDEC] = NULL; AssignmentFoldingFunction[EINDIRECT] = NULL; AssignmentFoldingFunction[EMONMIN] = NULL; AssignmentFoldingFunction[EBINNOT] = NULL; AssignmentFoldingFunction[ELOGNOT] = NULL; AssignmentFoldingFunction[EFORCELOAD] = NULL; AssignmentFoldingFunction[EMUL] = NULL; AssignmentFoldingFunction[EMULV] = NULL; AssignmentFoldingFunction[EDIV] = NULL; AssignmentFoldingFunction[EMODULO] = NULL; AssignmentFoldingFunction[EADDV] = NULL; AssignmentFoldingFunction[ESUBV] = NULL; AssignmentFoldingFunction[EADD] = NULL; AssignmentFoldingFunction[ESUB] = NULL; AssignmentFoldingFunction[ESHL] = NULL; AssignmentFoldingFunction[ESHR] = NULL; AssignmentFoldingFunction[ELESS] = NULL; AssignmentFoldingFunction[EGREATER] = NULL; AssignmentFoldingFunction[ELESSEQU] = NULL; AssignmentFoldingFunction[EGREATEREQU] = NULL; AssignmentFoldingFunction[EEQU] = NULL; AssignmentFoldingFunction[ENOTEQU] = NULL; AssignmentFoldingFunction[EAND] = NULL; AssignmentFoldingFunction[EXOR] = NULL; AssignmentFoldingFunction[EOR] = NULL; AssignmentFoldingFunction[ELAND] = NULL; AssignmentFoldingFunction[ELOR] = NULL; AssignmentFoldingFunction[EASS] = NULL; AssignmentFoldingFunction[EMULASS] = CInt64_Mul; AssignmentFoldingFunction[EDIVASS] = CInt64_Mul; AssignmentFoldingFunction[EMODASS] = NULL; AssignmentFoldingFunction[EADDASS] = CInt64_Add; AssignmentFoldingFunction[ESUBASS] = CInt64_Add; AssignmentFoldingFunction[ESHLASS] = CInt64_Add; AssignmentFoldingFunction[ESHRASS] = CInt64_Add; AssignmentFoldingFunction[EANDASS] = CInt64_And; AssignmentFoldingFunction[EXORASS] = CInt64_Xor; AssignmentFoldingFunction[EORASS] = CInt64_Or; AssignmentFoldingFunction[ECOMMA] = NULL; AssignmentFoldingFunction[EPMODULO] = NULL; AssignmentFoldingFunction[EROTL] = NULL; AssignmentFoldingFunction[EROTR] = NULL; AssignmentFoldingFunction[EBCLR] = NULL; AssignmentFoldingFunction[EBTST] = NULL; AssignmentFoldingFunction[EBSET] = NULL; AssignmentFoldingFunction[ETYPCON] = NULL; AssignmentFoldingFunction[EBITFIELD] = NULL; AssignmentFoldingFunction[EINTCONST] = NULL; AssignmentFoldingFunction[EFLOATCONST] = NULL; AssignmentFoldingFunction[ESTRINGCONST] = NULL; AssignmentFoldingFunction[ECOND] = NULL; AssignmentFoldingFunction[EFUNCCALL] = NULL; AssignmentFoldingFunction[EFUNCCALLP] = NULL; AssignmentFoldingFunction[EOBJREF] = NULL; AssignmentFoldingFunction[EMFPOINTER] = NULL; AssignmentFoldingFunction[ENULLCHECK] = NULL; AssignmentFoldingFunction[EPRECOMP] = NULL; AssignmentFoldingFunction[ETEMP] = NULL; AssignmentFoldingFunction[EARGOBJ] = NULL; AssignmentFoldingFunction[ELOCOBJ] = NULL; AssignmentFoldingFunction[ELABEL] = NULL; AssignmentFoldingFunction[ESETCONST] = NULL; AssignmentFoldingFunction[ENEWEXCEPTION] = NULL; AssignmentFoldingFunction[ENEWEXCEPTIONARRAY] = NULL; AssignmentFoldingFunction[EOBJLIST] = NULL; AssignmentFoldingFunction[EMEMBER] = NULL; AssignmentFoldingFunction[ETEMPLDEP] = NULL; AssignmentFoldingFunction[EINSTRUCTION] = NULL; AssignmentFoldingFunction[EDEFINE] = NULL; AssignmentFoldingFunction[EREUSE] = NULL; AssignmentFoldingFunction[EASSBLK] = NULL; AssignmentFoldingFunction[EVECTOR128CONST] = NULL; AssignmentFoldingFunction[ECONDASS] = NULL; } static void UpdateUseForOtherSelfAssignment(IROLinear *a, IROLinear *b, Type *type) { CInt64 val; IROLinear *father; IROLinear *repl; IROLinear *newdiadic; val = IRO_GetSelfAssignmentVal(b); if ((father = IRO_LocateFather(a)) && father->type == IROLinearOp2Arg && IRO_IsIntConstant(father->u.diadic.right)) { CInt64 var_30 = father->u.diadic.right->u.node->data.intval; if (AssignmentFoldingFunction[b->nodetype] && ((father->nodetype == b->nodetype) || (father->nodetype == IRO_NonAssignmentOp[b->nodetype]))) { CInt64 v; CInt64 folded; CInt64_SetLong(&v, b->rtype->size * 8); folded = AssignmentFoldingFunction[b->nodetype](var_30, val); if (b->nodetype == ESHRASS && !is_unsigned(b->rtype)) { if (CInt64_LessU(var_30, v) && CInt64_LessU(val, v)) { if (CInt64_GreaterEqualU(folded, v)) folded = CInt64_Sub(v, cint64_one); father->u.diadic.right->u.node->data.intval = folded; return; } } else { father->u.diadic.right->u.node->data.intval = folded; return; } } else { switch (b->nodetype) { case EMULASS: if (father->nodetype == ESHL || father->nodetype == ESHLASS) { SInt32 powvalue; if (IRO_IsPow2(b->u.diadic.right, &powvalue)) { if (powvalue > 0) { CInt64 v; CInt64_SetLong(&v, powvalue); father->u.diadic.right->u.node->data.intval = CInt64_Add(v, var_30); } } else { father->nodetype = (father->nodetype == ESHL) ? EMUL : EMULASS; var_30 = CInt64_Shl(cint64_one, var_30); father->u.diadic.right->u.node->data.intval = CInt64_Mul(var_30, val); } return; } break; case EDIVASS: if ((father->nodetype == ESHR || father->nodetype == ESHRASS) && is_unsigned(father->rtype)) { SInt32 powvalue; if (IRO_IsPow2(b->u.diadic.right, &powvalue)) { if (powvalue > 0) { CInt64 v; CInt64_SetLong(&v, powvalue); father->u.diadic.right->u.node->data.intval = CInt64_Add(v, var_30); } } else { father->nodetype = (father->nodetype == ESHR) ? EDIV : EDIVASS; var_30 = CInt64_Shl(cint64_one, var_30); father->u.diadic.right->u.node->data.intval = CInt64_Mul(var_30, val); } return; } break; case ESHLASS: if (father->nodetype == EMUL || father->nodetype == EMULASS) { SInt32 powvalue; if (IRO_IsPow2(father->u.diadic.right, &powvalue)) { if (powvalue > 0) { CInt64 v; father->nodetype = (father->nodetype == EMUL) ? ESHL : ESHLASS; CInt64_SetLong(&v, powvalue); father->u.diadic.right->u.node->data.intval = CInt64_Add(v, val); } } else { val = CInt64_Shl(cint64_one, val); father->u.diadic.right->u.node->data.intval = CInt64_Mul(var_30, val); } return; } else if (father->nodetype == ESHR || father->nodetype == ESHRASS) { if (CInt64_Equal(var_30, val) && is_unsigned(father->rtype)) { father->nodetype = (father->nodetype == ESHR) ? EAND : EANDASS; if (father->rtype->size < 8) { CInt64 v; CInt64_SetLong(&v, 64 - (father->rtype->size * 8)); val = CInt64_Add(val, v); } father->u.diadic.right->u.node->data.intval = CInt64_ShrU(cint64_negone, val); return; } } break; case ESHRASS: if ((father->nodetype == EDIV || father->nodetype == EDIVASS) && is_unsigned(father->rtype)) { SInt32 powvalue; if (IRO_IsPow2(father->u.diadic.right, &powvalue)) { if (powvalue > 0) { CInt64 v; father->nodetype = (father->nodetype == EDIV) ? ESHR : ESHRASS; CInt64_SetLong(&v, powvalue); father->u.diadic.right->u.node->data.intval = CInt64_Add(v, val); } } else { val = CInt64_Shl(cint64_one, val); father->u.diadic.right->u.node->data.intval = CInt64_Mul(var_30, val); } return; } else if (father->nodetype == ESHL || father->nodetype == ESHLASS) { if (CInt64_Equal(var_30, val)) { father->nodetype = (father->nodetype == ESHL) ? EAND : EANDASS; father->u.diadic.right->u.node->data.intval = CInt64_Shl(cint64_negone, val); return; } } break; } } } repl = IRO_NewIntConst(val, type); newdiadic = IRO_NewLinear(IROLinearOp2Arg); newdiadic->index = ++IRO_NumLinear; newdiadic->nodetype = IRO_NonAssignmentOp[b->nodetype]; newdiadic->u.diadic.left = a; newdiadic->u.diadic.right = repl; newdiadic->rtype = a->rtype; repl->next = newdiadic; IRO_LocateFather_Cut_And_Paste_Without_Nopping(a, newdiadic); IRO_PasteAfter(repl, newdiadic, a); } static Boolean PropagateIncsAndDecs(void) { IRODef *def; Boolean result; result = 0; def = FirstDef; while (def) { if ( def->linear && def->x1C && IsIncOrDec(def->linear) && !(def->linear->flags & IROLF_Reffed) && (IS_TYPE_INT_OR_ENUM(def->linear->rtype) || IS_TYPE_POINTER_ONLY(def->linear->rtype)) && IRO_TypesEqual(def->linear->rtype, def->var->object->type) && !is_volatile_object(def->var->object) ) { IROUse *use; IROUse *use2; IROLinear *father; CInt64 val; SInt32 i; Type *type; for (use = def->var->uses, i = 0; use; use = use->varnext) { if (Bv_IsBitSet(def->index, use->x18)) { if ( use->x1C == 1 && use->linear->type == IROLinearOperand && (father = IRO_LocateFather(use->linear)) && IRO_IsVariable(father) && IRO_TypesEqual(def->linear->rtype, father->rtype) ) { if (use->linear->flags & IROLF_Assigned) { if (!((father = IRO_LocateFather(father)) && IsIncOrDec(father) && !(father->flags & IROLF_Reffed))) goto nextDef; } i++; } else { goto nextDef; } } } if (i == def->x18) { for (use = def->var->uses; use; use = use->varnext) { if (Bv_IsBitSet(def->index, use->x18)) { IRO_Dump("Propagating inc/dec from %d to %d\n", def->linear->index, use->linear->index); father = IRO_LocateFather(use->linear); val = IRO_GetSelfAssignmentVal(def->linear); type = def->linear->rtype; if (IS_TYPE_POINTER_ONLY(def->linear->rtype)) type = TYPE(&stunsignedlong); UpdateUse(father, val, type); result = 1; for (use2 = def->var->uses; use2; use2 = use2->varnext) { if (use2->linear == def->linear->u.monadic->u.diadic.left) { use->x1C = use2->x1C; Bv_Copy(use2->x18, use->x18); break; } } } } def->x18 = 0; IRO_NopNonSideEffects(def->linear, -1); def->linear->type = IROLinearNop; IRO_Dump("Removing deadddd assignment %d\n", def->linear->index); } } nextDef: def = def->globalnext; } return result; } static Boolean PropagateOtherSelfAssignments(void) { IRODef *def; Boolean result; result = 0; def = FirstDef; while (def) { if ( def->linear && def->x1C && IsOtherSelfAssignment(def->linear) && !(def->linear->flags & IROLF_Reffed) && IS_TYPE_INT_OR_ENUM(def->linear->rtype) && IRO_TypesEqual(def->linear->rtype, def->var->object->type) && !is_volatile_object(def->var->object) ) { IROUse *use; IROUse *use2; IROLinear *father; SInt32 i; Type *type; for (use = def->var->uses, i = 0; use; use = use->varnext) { if (Bv_IsBitSet(def->index, use->x18)) { if ( use->x1C == 1 && use->linear->type == IROLinearOperand && (father = IRO_LocateFather(use->linear)) && IRO_IsVariable(father) && IRO_TypesEqual(def->linear->rtype, father->rtype) ) { if (use->linear->flags & IROLF_Assigned) { if (!((father = IRO_LocateFather(father)) && IsOtherSelfAssignment(father) && (father->nodetype == def->linear->nodetype) && !(father->flags & IROLF_Reffed))) goto nextDef; } i++; } else { goto nextDef; } } } if (i == def->x18) { for (use = def->var->uses; use; use = use->varnext) { if (Bv_IsBitSet(def->index, use->x18)) { IRO_Dump("Propagating self assignment from %d to %d\n", def->linear->index, use->linear->index); father = IRO_LocateFather(use->linear); UpdateUseForOtherSelfAssignment(father, def->linear, def->linear->rtype); result = 1; for (use2 = def->var->uses; use2; use2 = use2->varnext) { if (use2->linear == def->linear->u.monadic->u.diadic.left) { use->x1C = use2->x1C; Bv_Copy(use2->x18, use->x18); break; } } } } def->x18 = 0; IRO_NopNonSideEffects(def->linear, -1); def->linear->type = IROLinearNop; IRO_Dump("Removing deadddd assignment %d\n", def->linear->index); } } nextDef: def = def->globalnext; } return result; } static void MarkUsesByIndirect(IROLinear *linear, BitVector *a, BitVector *b) { IROListNode *list; IROLinear *nd; Object *obj; VarRecord *var; Boolean foundObjRef; IROListNode *scan; IRODef *def; Boolean found; found = 0; if (linear && copts.opt_pointer_analysis && linear->pointsToFunction && FunctionName) { IROListNode *resultList; resultList = NULL; PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, linear, &resultList); if ((list = resultList)) { for (scan = list; scan; scan = scan->nextList) { if (!scan->list.head || !scan->list.tail) { found = 1; break; } foundObjRef = 0; for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) { if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { foundObjRef = 1; break; } } if (!foundObjRef) { found = 1; break; } } if (!found) { while (list) { for (nd = list->list.head; nd != list->list.tail->next; nd = nd->next) { if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { obj = nd->u.node->data.objref; CError_ASSERT(1422, obj != NULL); var = IRO_FindVar(obj, 1, 1); CError_ASSERT(1424, var != NULL); for (def = var->defs; def; def = def->varnext) { if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches))) { def->x18++; Bv_SetBit(def->index, MightReachAnyUse); } } } } list = list->nextList; } } while (resultList) { IROListNode *next = resultList->nextList; IRO_free(resultList); resultList = next; } } else { found = 1; } } else { found = 1; } if (found) { Bv_Copy(Reaches, a); Bv_And(b, a); Bv_Or(a, MightReachAnyUse); for (def = FirstDef; def; def = def->globalnext) { if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches))) def->x18++; } } } static void MarkUsesByFunctionCall(IROLinear *linear, BitVector *a, BitVector *b) { ObjectList *olist; IROLinear *funcnd; IROListNode *list; IROLinear *nd; Object *obj; VarRecord *var; Boolean foundObjRef; IROListNode *scan; IRODef *def; Boolean found; found = 0; if ((funcnd = linear->u.funccall.linear8) && copts.opt_pointer_analysis && funcnd->pointsToFunction && FunctionName) { IROListNode *resultList; ObjectList *depsList; resultList = NULL; PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, funcnd, &resultList); if (resultList) { for (scan = resultList; scan; scan = scan->nextList) { if (!scan->list.head || !scan->list.tail) { found = 1; break; } foundObjRef = 0; for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) { if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { foundObjRef = 1; obj = nd->u.node->data.objref; CError_ASSERT(1522, obj != NULL); depsList = NULL; PointerAnalysis_GetFunctionDependencies(obj, linear, &depsList); for (olist = depsList; olist; olist = olist->next) { if (!olist->object) { found = 1; break; } } while (depsList) { olist = depsList->next; IRO_free(depsList); depsList = olist; } if (found) break; } } if (!foundObjRef) found = 1; if (found) break; } if (!found) { for (list = resultList; list; list = list->nextList) { for (nd = list->list.head; nd != list->list.tail->next; nd = nd->next) { if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { obj = nd->u.node->data.objref; depsList = NULL; PointerAnalysis_GetFunctionDependencies(obj, linear, &depsList); for (olist = depsList; olist; olist = olist->next) { var = IRO_FindVar(olist->object, 1, 1); CError_ASSERT(1573, var != NULL); for (def = var->defs; def; def = def->varnext) { if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches))) { def->x18++; Bv_SetBit(def->index, MightReachAnyUse); } } } while (depsList) { olist = depsList->next; IRO_free(depsList); depsList = olist; } } } } } while (resultList) { IROListNode *next = resultList->nextList; IRO_free(resultList); resultList = next; } } else { found = 1; } } else { found = 1; } if (found) { Bv_Copy(Reaches, a); Bv_And(b, a); Bv_Or(a, MightReachAnyUse); for (def = FirstDef; def; def = def->globalnext) { if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches))) def->x18++; } } if (linear->stmt && IRO_FunctionCallMightThrowException(linear)) IRO_WalkExcActions(linear->stmt->dobjstack, MarkUses); } static Boolean UseOfVarIsInsideASimpleDefOfVar(IROUse *use) { VarRecord *var; VarRecord *varAss; IROLinear *nd; IROLinear *nd2; if ((var = use->var)) { if ((nd = use->linear) && (nd->flags & IROLF_4000)) return 0; while (nd && (nd->flags & IROLF_Reffed)) nd = nd->next; if ( nd && IRO_IsAssignment(nd) && (varAss = IRO_FindAssigned(nd)) && varAss == var && !IRO_HasSideEffect((nd->type == IROLinearOp1Arg) ? nd->u.monadic : nd->u.diadic.left) && (!(nd2 = (nd->type == IROLinearOp1Arg) ? NULL : nd->u.diadic.right) || !IRO_HasSideEffect(nd2)) ) { return 1; } } return 0; } static Boolean AllLoopDefUsesAreInSimpleLoopDefs(IRODef *def) { VarRecord *var; IRODef *scan; IROUse *use; if ((var = def->var)) { for (scan = var->defs; scan; scan = scan->varnext) { if (scan->node && scan->node->loopdepth) { for (use = var->uses; use; use = use->varnext) { if (Bv_IsBitSet(scan->index, use->x18)) { if (!use->node || !use->node->loopdepth || !UseOfVarIsInsideASimpleDefOfVar(use)) return 0; } } } } return 1; } else { return 0; } } static void MarkRemovableLoopDefs(void) { IRODef *def; IRODef *scan; for (def = FirstDef; def; def = def->globalnext) { if (!def->x1A && !def->x1B && def->node && def->node->loopdepth && !def->x1D && AllLoopDefUsesAreInSimpleLoopDefs(def) && def->var) { for (scan = def->var->defs; scan; scan = scan->varnext) { if (scan->node && scan->node->loopdepth) scan->x1D = 1; } } } } static Boolean EliminateReffedDeadStore(IRODef *def) { Boolean isPostIncOrDec; IROLinear *nd; Boolean result; nd = def->linear; isPostIncOrDec = (nd->type == IROLinearOp1Arg) && (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC); result = IRO_LocateFather(nd) != NULL; if (result && IRO_IsAssignment(nd) && IRO_IsModifyOp[nd->nodetype]) result = IRO_TransformSelfAssignmentToAssignment(nd); result = result && (nd->type == IROLinearOp2Arg) && (nd->nodetype == EASS); if (result) { def->x18 = 0; IRO_Dump("Removing referenced dead assignment %d\n", nd->index); if (isPostIncOrDec) { IRO_NopNonSideEffects(nd->u.diadic.right, 0); nd->type = IROLinearNop; IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, nd->u.diadic.left); } else { IRO_NopNonSideEffects(nd->u.diadic.left, 0); nd->type = IROLinearNop; IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, nd->u.diadic.right); } } return result; } Boolean IRO_UseDef(Boolean optDeadAssignments, Boolean optPropagation) { Boolean result; IRODef *gdef; IROUse *guse; IRODef *def; IROUse *use; IRONode *node; IROLinear *nd; VarRecord *var; Boolean flag; BitVector *bv3; BitVector *bv2; BitVector *bv; int i; FindDefsAndUses(); IRO_CheckForUserBreak(); for (use = IRO_FirstVarUse; use; use = use->globalnext) Bv_AllocVector(&use->x18, NumDefs); Bv_AllocVector(&MightReachAnyUse, NumDefs); Bv_AllocVector(&bv, NumDefs); IRO_CheckForUserBreak(); for (def = FirstDef; def; def = def->globalnext) { if (def->x1A || def->x1B) Bv_SetBit(def->index, bv); } Bv_AllocVector(&bv2, NumDefs); gdef = FirstDef; for (node = IRO_FirstNode; node; node = node->nextnode) { Bv_AllocVector(&node->x16, NumDefs); Bv_AllocVector(&node->x1E, NumDefs); Bv_AllocVector(&node->x22, NumDefs); Bv_AllocVector(&node->x1A, NumDefs); for (nd = node->first; nd; nd = nd->next) { while (gdef && gdef->linear == nd) { Bv_SetBit(gdef->index, node->x1E); if (gdef->x1C) { for (def = gdef->var->defs; def; def = def->varnext) { if (def != gdef) { Bv_SetBit(def->index, node->x22); Bv_ClearBit(def->index, node->x1E); } } } gdef = gdef->globalnext; } if (nd == node->last) break; } if (node->numpred) Bv_Set(node->x16); Bv_Copy(node->x1E, node->x1A); IRO_CheckForUserBreak(); } Bv_AllocVector(&bv3, NumDefs); do { flag = 0; for (node = IRO_FirstNode; node; node = node->nextnode) { Bv_Clear(node->x16); if (node->numpred) { for (i = 0; i < node->numpred; i++) Bv_Or(IRO_NodeTable[node->pred[i]]->x1A, node->x16); } else if (node == IRO_FirstNode) { for (var = IRO_FirstVar; var; var = var->next) Bv_SetBit(var->defs->index, node->x16); } Bv_Copy(node->x16, bv3); Bv_Minus(node->x22, bv3); Bv_Or(node->x1E, bv3); if (!Bv_Compare(bv3, node->x1A)) { Bv_Copy(bv3, node->x1A); flag = 1; } } IRO_CheckForUserBreak(); } while (flag); gdef = FirstDef; guse = IRO_FirstVarUse; Bv_AllocVector(&Reaches, NumDefs); for (node = IRO_FirstNode; node; node = node->nextnode) { Bv_Copy(node->x16, Reaches); nd = node->first; while (1) { while (guse && guse->linear == nd) { for (def = guse->var->defs; def; def = def->varnext) { if (Bv_IsBitSet(def->index, Reaches)) { Bv_SetBit(def->index, guse->x18); Bv_SetBit(def->index, MightReachAnyUse); def->x18++; guse->x1C++; } } guse = guse->globalnext; } if (nd->type == IROLinearFunccall) { MarkUsesByFunctionCall(nd, bv2, bv); } else if (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT && !IRO_IsVariable(nd)) { MarkUsesByIndirect(nd, bv2, bv); } else if ((nd->type == IROLinearFunccall) || (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT && !IRO_IsVariable(nd))) { Bv_Copy(Reaches, bv2); Bv_And(bv, bv2); Bv_Or(bv2, MightReachAnyUse); for (def = FirstDef; def; def = def->globalnext) { if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches))) def->x18++; } if (nd->type == IROLinearFunccall && nd->stmt && IRO_FunctionCallMightThrowException(nd)) IRO_WalkExcActions(nd->stmt->dobjstack, MarkUses); } if (nd->type == IROLinearAsm) { IAEffects effects; CodeGen_GetAsmEffects(nd->u.asm_stmt, &effects); if (effects.x2) { Bv_Copy(Reaches, bv2); Bv_And(bv, bv2); Bv_Or(bv2, MightReachAnyUse); } } if (nd->type == IROLinearReturn || nd->type == IROLinearEnd) { for (def = FirstDef; def; def = def->globalnext) { if (def->x1A && Bv_IsBitSet(def->index, Reaches)) { Bv_SetBit(def->index, MightReachAnyUse); def->x18++; } } } while (gdef && gdef->linear == nd) { if (gdef->x1C) { for (def = gdef->var->defs; def; def = def->varnext) Bv_ClearBit(def->index, Reaches); } Bv_SetBit(gdef->index, Reaches); gdef = gdef->globalnext; } if (nd == node->last) break; nd = nd->next; } } IRO_CheckForUserBreak(); result = 0; if (optDeadAssignments) { MarkRemovableLoopDefs(); for (def = FirstDef; def; def = def->globalnext) { if (def->linear && (!Bv_IsBitSet(def->index, MightReachAnyUse) || def->x1D) && (copts.opt_pointer_analysis || !def->x1B) && def->linear->type != IROLinearAsm && (!def->linear->rtype || !CParser_IsVolatile(def->linear->rtype, def->linear->nodeflags & ENODE_FLAG_QUALS)) && !is_volatile_object(def->var->object) ) { if (!(def->linear->flags & IROLF_Reffed)) { def->x18 = 0; IRO_NopNonSideEffects(def->linear, -1); def->linear->type = IROLinearNop; IRO_Dump("Removing dead assignment %d\n", def->linear->index); result = 1; } else { result = EliminateReffedDeadStore(def); } } } } IRO_CheckForUserBreak(); if (optPropagation) { while (1) { if (PropagateIncsAndDecs() || PropagateOtherSelfAssignments()) result = 1; else break; } } IRO_CheckForUserBreak(); return result; } static IROLinear *GetOperand(IROLinear *nd) { IROLinear *inner; if (nd->type == IROLinearOperand) return nd; if (nd->type == IROLinearOp2Arg && nd->nodetype == EADD) { inner = GetOperand(nd->u.diadic.left); if (!inner) inner = GetOperand(nd->u.diadic.right); return inner; } return NULL; } static IROLinear *GetAssigned(IROLinear *nd) { if (!nd) return NULL; if (nd->type == IROLinearOp2Arg) nd = nd->u.diadic.left; else if (nd->type == IROLinearOp1Arg) nd = nd->u.monadic; else CError_FATAL(2338); if (nd->type != IROLinearOp1Arg || nd->nodetype != EINDIRECT) CError_FATAL(2351); nd = nd->u.monadic; if (nd->type == IROLinearOp2Arg && nd->nodetype == EADD) nd = GetOperand(nd); return nd; } static void AddUseToRange(IROUse *use) { IRODef *def; Bv_SetBit(use->index, useset); Bv_ClearBit(use->index, alluses); for (def = use->var->defs; def; def = def->varnext) { if (Bv_IsBitSet(def->index, alldefs) && (Bv_IsBitSet(def->index, use->x18) || GetAssigned(def->linear) == use->linear)) AddDefToRange(def); } } static void AddDefToRange(IRODef *def) { IROUse *use; IROLinear *assigned; Bv_SetBit(def->index, defset); Bv_ClearBit(def->index, alldefs); for (use = def->var->uses, assigned = GetAssigned(def->linear); use; use = use->varnext) { if (Bv_IsBitSet(use->index, alluses) && (Bv_IsBitSet(def->index, use->x18) || assigned == use->linear)) AddUseToRange(use); } } static void ReplaceAssigned(IROLinear *nd, Object *from, Object *to) { IROLinear *assigned; if ( !(assigned = GetAssigned(nd)) || assigned->type != IROLinearOperand || assigned->u.node->type != EOBJREF || assigned->u.node->data.objref != from ) CError_FATAL(2459); assigned->u.node->data.objref = to; } static void ReplaceUsed(IROLinear *nd, Object *from, Object *to) { CError_ASSERT(2482, nd->type == IROLinearOperand && nd->u.node->type == EOBJREF); if (nd->u.node->data.objref == from) nd->u.node->data.objref = to; else if (nd->u.node->data.objref != to) CError_FATAL(2494); } static void SplitOffRange(VarRecord *var) { Object *newObj; IRODef *def; IROUse *use; IRO_Dump("Splitting range for variable: %d\n", var->index); IRO_DumpBits("Def set: ", defset); IRO_DumpBits("Use set: ", useset); IRO_DumpBits("All defs: ", alldefs); IRO_DumpBits("All uses: ", alluses); newObj = create_temp_object(var->object->type); IRO_FindVar(newObj, 1, 1); for (def = var->defs; def; def = def->varnext) { if (Bv_IsBitSet(def->index, defset) && def->linear) ReplaceAssigned(def->linear, var->object, newObj); } for (use = var->uses; use; use = use->varnext) { if (Bv_IsBitSet(use->index, useset)) ReplaceUsed(use->linear, var->object, newObj); } } void IRO_SplitLifetimes(void) { VarRecord *var; SInt32 numVars; IRODef *def; IROUse *use; Boolean flag; Bv_AllocVector(&alldefs, NumDefs); Bv_AllocVector(&alluses, NumUses); Bv_AllocVector(&defset, NumDefs); Bv_AllocVector(&useset, NumUses); var = IRO_FirstVar; numVars = IRO_NumVars; while (var && var->index <= numVars) { if (var->object->datatype == DLOCAL && !is_volatile_object(var->object) && !var->xC && !var->xB && !var->x1E) { Bv_Clear(alldefs); Bv_Clear(alluses); for (def = var->defs; def; def = def->varnext) { if (def->linear && def->linear->type == IROLinearAsm) goto skipThisVar; Bv_SetBit(def->index, alldefs); } for (use = var->uses; use; use = use->varnext) { if (use->linear && use->linear->type == IROLinearAsm) goto skipThisVar; Bv_SetBit(use->index, alluses); } flag = 1; while (1) { Bv_Clear(defset); Bv_Clear(useset); def = var->defs; while (def && !Bv_IsBitSet(def->index, alldefs)) def = def->varnext; if (!def) break; AddDefToRange(def); if (Bv_IsEmpty(alldefs)) break; if (!flag) SplitOffRange(var); flag = 0; } } skipThisVar: var = var->next; } IRO_CheckForUserBreak(); }