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