diff options
author | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
---|---|---|
committer | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
commit | 094b96ca1df4a035b5f93c351f773306c0241f3f (patch) | |
tree | 95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/FrontEnd/Optimizer | |
parent | fc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff) | |
download | MWCC-094b96ca1df4a035b5f93c351f773306c0241f3f.tar.gz MWCC-094b96ca1df4a035b5f93c351f773306c0241f3f.zip |
move lots of source files around to match their actual placement in the original treemain
Diffstat (limited to 'compiler_and_linker/FrontEnd/Optimizer')
43 files changed, 30734 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/Optimizer/BitVector.h b/compiler_and_linker/FrontEnd/Optimizer/BitVector.h new file mode 100644 index 0000000..a6830d6 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/BitVector.h @@ -0,0 +1,36 @@ +#ifndef COMPILER_IROBITVECT_H +#define COMPILER_IROBITVECT_H + +#include "compiler/common.h" +#include "compiler/CError.h" + +typedef struct BitVector { + UInt32 size; + UInt32 data[0]; +} BitVector; + +extern void Bv_AllocVector(BitVector **bv, UInt32 size); +extern void Bv_AllocVectorLocal(BitVector **bv, UInt32 size); +extern void Bv_ClearBit(UInt32 bit, BitVector *bv); +extern void Bv_And(const BitVector *a, BitVector *b); +extern void Bv_Or(const BitVector *a, BitVector *b); +extern Boolean Bv_BitsInCommon(const BitVector *a, const BitVector *b); +extern Boolean Bv_Compare(const BitVector *a, const BitVector *b); +extern void Bv_Minus(const BitVector *a, BitVector *b); +extern void Bv_Copy(const BitVector *src, BitVector *dst); +extern void Bv_Clear(BitVector *bv); +extern void Bv_Set(BitVector *bv); +extern Boolean Bv_IsSubset(const BitVector *a, const BitVector *b); +extern Boolean Bv_IsEmpty(const BitVector *bv); + +CW_INLINE void Bv_SetBit(UInt32 bit, BitVector *bv) { + if ((bit / 32) < bv->size) { + bv->data[bit / 32] |= 1 << (bit & 31); + } else { + CError_FATAL(56); + } +} + +#define Bv_IsBitSet(_bit, _bv) ( (((_bit) >> 5) < (_bv)->size) && ((_bv)->data[(_bit) >> 5] & (1 << ((_bit) & 31))) ) + +#endif 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(); +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IROUseDef.h b/compiler_and_linker/FrontEnd/Optimizer/IROUseDef.h new file mode 100644 index 0000000..03d3f9b --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IROUseDef.h @@ -0,0 +1,48 @@ +#ifndef COMPILER_IROUSEDEF_H +#define COMPILER_IROUSEDEF_H + +#include "IrOptimizer.h" +#include "BitVector.h" +#include "compiler/enode.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +struct IROUse { + SInt32 index; + IRONode *node; + IROLinear *linear; + VarRecord *var; + IROUse *globalnext; + IROUse *varnext; + BitVector *x18; + UInt16 x1C; +}; +struct IRODef { + SInt32 index; + IRONode *node; + IROLinear *linear; + VarRecord *var; + IRODef *globalnext; + IRODef *varnext; + UInt16 x18; + Boolean x1A; + Boolean x1B; + Boolean x1C; + Boolean x1D; +}; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +extern ENodeType IRO_NonAssignmentOp[MAXEXPR]; +extern IROUse *IRO_FirstVarUse; +extern IROUse *IRO_LastVarUse; + +extern CInt64 IRO_GetSelfAssignmentVal(IROLinear *linear); +extern void IRO_InitializeNonAssignmentOpArray(void); +extern void IRO_InitializeAssignmentFoldingFunctionArray(void); +extern Boolean IRO_UseDef(Boolean optDeadAssignments, Boolean optPropagation); +extern void IRO_SplitLifetimes(void); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.c b/compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.c new file mode 100644 index 0000000..59bb368 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.c @@ -0,0 +1,400 @@ +#include "IrOptimizer.h" +#include "compiler/CError.h" +#include "compiler/CParser.h" +#include "compiler/InlineAsmPPC.h" +#include "IroCSE.h" +#include "IroDump.h" +#include "IroEval.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroSubable.h" +#include "IroTransform.h" +#include "IROUseDef.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/objects.h" +#include "IroPropagate.h" +#include "IroPointerAnalysis.h" +#include "IroJump.h" +#include "IroRangePropagation.h" +#include "IroEmptyLoop.h" +#include "IroUnrollLoop.h" +#include "IroLoop.h" +#include "IroExprRegeneration.h" + +Boolean DoScalarize; +Boolean DoLinearize; +Boolean EarlyReturn; +Boolean IRO_CPFirstTime; +Boolean VectorPhaseCalledFromUnroll; +Boolean IRO_Log; +static Boolean stIsSetup; + +static void CountRefToObject(Object *object, int depth) { + static unsigned short LoopUsage[] = {1, 4, 16, 64}; + + if (depth > 3) + depth = 3; + + object->u.var.info->usage += LoopUsage[depth]; + object->u.var.info->used = 1; +} + +static void CountARef(IROLinear *node, int depth) { + Object *object; + + object = node->u.node->data.objref; + CError_ASSERT(78, object->datatype != DALIAS); + + if (object->datatype == DLOCAL && object->u.var.info) { + CountRefToObject(object, depth); + if ((node->flags & IROLF_Used) && (node->flags & IROLF_Assigned)) + CountRefToObject(object, depth); + + if (!(node->flags & IROLF_Immind) && !object->u.var.info->noregister) + object->u.var.info->noregister = 2; + } +} + +static void CountDoubleInd(IROLinear *node, int depth) { + if (IRO_IsVariable(node)) { + CountARef(node->u.monadic, depth); + } else if (node->type == IROLinearOp2Arg) { + if (node->nodetype == EADD) { + CountDoubleInd(node->u.diadic.left, depth); + CountDoubleInd(node->u.diadic.right, depth); + } else if (IRO_IsAddressMultiply(node)) { + if (IRO_IsVariable(node->u.diadic.left)) + CountARef(node->u.diadic.left->u.monadic, depth); + } + } +} + +static void CountUsage(void) { + IRONode *fnode = IRO_FirstNode; + IROLinear *node; + + if (IRO_FirstNode) { + for (; fnode; fnode = fnode->nextnode) { + for (node = fnode->first; node; node = node->next) { + if (IS_LINEAR_ENODE(node, EOBJREF)) + CountARef(node, fnode->loopdepth); + else if (IS_LINEAR_MONADIC(node, EINDIRECT)) + CountDoubleInd(node->u.monadic, fnode->loopdepth); + + if (node->type == IROLinearAsm) { + IAEffects effects; + int i; + + CodeGen_GetAsmEffects(node->u.asm_stmt, &effects); + for (i = 0; i < effects.numoperands; i++) { + Object *object = effects.operands[i].object; + if (object->datatype == DLOCAL && object->u.var.info) { + CountRefToObject(object, fnode->loopdepth); + if (effects.operands[i].type == IAOpnd_3 && !object->u.var.info->noregister) + object->u.var.info->noregister = 2; + } + } + } + + if (node == fnode->last) + break; + } + } + } else { + for (node = IRO_FirstLinear; node; node = node->next) { + if (IS_LINEAR_ENODE(node, EOBJREF)) + CountARef(node, 0); + else if (IS_LINEAR_MONADIC(node, EINDIRECT)) + CountDoubleInd(node->u.monadic, 0); + } + } + + IRO_CheckForUserBreak(); +} + +Statement *IRO_Optimizer(Object *func, Statement *statements) { + Boolean changed; + int pass; + int passCount; + + CError_ASSERT(234, stIsSetup); + +#ifdef CW_ENABLE_IRO_DEBUG + if (copts.debuglisting) + IRO_Log = 1; +#endif + + DisableDueToAsm = 0; + FunctionName = func; + DoScalarize = 1; + DoLinearize = 1; + EarlyReturn = 0; + IRO_Depends = NULL; + LoopOptimizerRun = 0; + IRO_IsLeafFunction = 1; + IRO_FunctionHasReturn = 0; + + IRO_SetupForUserBreakChecking(); + + IRO_Dump("Starting function %s\n", func ? func->name->name : "Init-code"); + IRO_Dump("--------------------------------------------------------------------------------\n"); + + if (DoLinearize) + IRO_PreLinearize(statements); + if (copts.optimizationlevel > 0) + IRO_TransformTree(statements); + + VectorPhaseCalledFromUnroll = 0; + + IRO_Linearize(statements); + + CurStat = NULL; + + IRO_FirstExpr = NULL; + IRO_LastExpr = NULL; + IRO_FirstAssign = NULL; + IRO_LastAssign = NULL; + IRO_FirstVarUse = NULL; + IRO_LastVarUse = NULL; + IRO_FirstNode = NULL; + IRO_LastNode = NULL; + + if (copts.optimizationlevel > 0) + IRO_DoTransformations(); + + IRO_BuildFlowgraph(IRO_FirstLinear); + IRO_DumpAfterPhase("IRO_BuildflowGraph", 0); + + IRO_FindAllVars(); + IRO_CheckInit(); + + if (!DisableDueToAsm && copts.optimizationlevel > 0 && copts.opt_pointer_analysis && func) { + IRO_AnalyzePointers(func); + if (copts.propagation && IRO_EvaluateDefinitePointers(func)) { + IRO_UpdateFlagsOnInts(); + IRO_UpdateVars(); + IRO_DumpAfterPhase("IRO_EvaluateDefinitePointers", 0); + } + } + + if (copts.optimizationlevel > 0) { + changed = IRO_EvaluateConditionals(); + + if (!DisableDueToAsm) { + changed |= IRO_RemoveUnreachable(); + IRO_DumpAfterPhase("IRO_RemoveUnreachable", 0); + } + + changed |= IRO_RemoveRedundantJumps(); + IRO_DumpAfterPhase("IRO_RemoveRedundantJumps", 0); + + if (!DisableDueToAsm) { + changed |= IRO_RemoveLabels(); + IRO_DumpAfterPhase("IRO_RemoveLabels()", 0); + } + + if (changed) { + IRO_BuildFlowgraph(IRO_FirstLinear); + IRO_DumpAfterPhase("IRO_BuildflowGraph--1", 0); + } + } + + if (!DisableDueToAsm && copts.optimizationlevel > 0) { + passCount = copts.multiplepasses ? 2 : 1; + IRO_CPFirstTime = 1; + for (pass = 0; pass < passCount; pass++) { + IRO_Dump("*****************\n"); + IRO_Dump("Dumps for pass=%d\n", pass); + IRO_Dump("*****************\n"); + + if (DoScalarize) + IRO_ScalarizeClassDataMembers(); + IRO_DumpAfterPhase("IRO_ScalarizeClassDataMembers", 0); + + if (copts.propagation) { + IRO_CopyAndConstantPropagation(); + IRO_CPFirstTime = 0; + IRO_ExpressionPropagation(); + IRO_DumpAfterPhase("Copy and constant propagation", 0); + + IRO_RangePropagateInFNode(); + IRO_DumpAfterPhase("IRO_RangePropagateInFNode", 0); + IRO_UpdateFlagsOnInts(); + } + + IRO_DumpAfterPhase("IRO_ExpressionPropagation", 0); + + if (copts.deadstore || copts.propagation) + IRO_UseDef(copts.deadstore, copts.propagation); + IRO_DumpAfterPhase("after IRO_UseDef", 0); + + IRO_UpdateVars(); + IRO_ConstantFolding(); + IRO_DumpAfterPhase("IRO_ConstantFolding", 0); + + IRO_EvaluateConditionals(); + IRO_RemoveUnreachable(); + IRO_SimplifyConditionals(); + + if (pass == 1 && copts.optimizationlevel > 2) { + IRO_RenumberInts(); + IRO_DumpAfterPhase("Before IRO_FindEmptyLoops", 0); + IRO_FindEmptyLoops(); + IRO_DumpAfterPhase("After IRO_FindEmptyLoops", 0); + IRO_RenumberInts(); + } + + if (copts.unrolling && !copts.optimizesize && pass == 0) { + IRO_DumpAfterPhase("Before IRO_LoopUnroller", 0); + IRO_LoopUnroller(); + IRO_DumpAfterPhase("After IRO_LoopUnroller", 0); + IRO_RenumberInts(); + } + + VectorPhaseCalledFromUnroll = 0; + + if (pass == 0 && (copts.loopinvariants || copts.strengthreduction)) { + IRO_DumpAfterPhase("Before IRO_FindLoops", 0); + IRO_FindLoops(); + LoopOptimizerRun = 1; + IRO_SetLoopDepth(); + } + IRO_DumpAfterPhase("After IRO_FindLoops", 0); + + if (copts.propagation) { + IRO_CopyAndConstantPropagation(); + IRO_ConstantFolding(); + IRO_EvaluateConditionals(); + } + + IRO_DumpAfterPhase("Second pass:IRO_CopyAndConstantPropagation, IRO_ConstantFolding, IRO_EvaluateConditionals", 0); + + if (copts.commonsubs) + IRO_FindExpressions(NULL, 0); + + if (copts.commonsubs) { + IRO_ComputeAvail(); + IRO_CommonSubs(); + } + IRO_DumpAfterPhase("IRO_CommonSubs", 0); + + IRO_UpdateFlagsOnInts(); + IRO_UpdateVars(); + IRO_DoTransformations(); + IRO_ConstantFolding(); + + do { + IRO_UpdateFlagsOnInts(); + + if (copts.deadcode) + IRO_RemoveUnreachable(); + IRO_DumpAfterPhase("IRO_RemoveUnreachable", 0); + + changed = IRO_RemoveRedundantJumps(); + IRO_DumpAfterPhase("IRO_RemoveRedundantJumps", 0); + + changed |= IRO_RemoveLabels(); + IRO_DumpAfterPhase("IRO_RemoveLabels", 0); + + changed |= IRO_DoJumpChaining(); + IRO_DumpAfterPhase("IRO_DoJumpChaining", 0); + + if (copts.propagation) { + IRO_RenumberInts(); + IRO_DumpAfterPhase("Before IRO_CopyAndConstantPropagation", 0); + changed |= IRO_CopyAndConstantPropagation(); + IRO_DumpAfterPhase("After IRO_CopyAndConstantPropagation", 0); + IRO_ConstantFolding(); + } + + if (copts.deadstore || copts.propagation) + changed |= IRO_UseDef(copts.deadstore, copts.propagation); + IRO_DumpAfterPhase("IRO_UseDef", 0); + + changed |= IRO_EvaluateConditionals(); + IRO_DumpAfterPhase("IRO_EvaluateConditionals", 0); + } while (changed); + } + + if (copts.lifetimes) { + IRO_UseDef(0, 0); + IRO_SplitLifetimes(); + } + + IRO_DoTransformations(); + IRO_DumpAfterPhase("Before RebuildCondExpressions", 0); + } + + IRO_RenumberInts(); + IRO_DumpAfterPhase("before IRO_RewriteBitFieldTemps", 0); + IRO_RewriteBitFieldTemps(); + IRO_DumpAfterPhase("After IRO_RewriteBitFieldTemps", 0); + + CountUsage(); + + if (!DisableDueToAsm) { + IRO_RegenerateExpressions(); + IRO_DumpAfterPhase("IRO_RegenerateExpressions", 0); + } + + IRO_DumpAfterPhase("After IRO_Optimizer", 0); + + statements = IRO_Delinearize(IRO_FirstNode, NULL); + + IRO_ZapVarPtrs(); + freeoheap(); + return statements; +} + +void IRO_Setup(void) { + static Boolean ENodeArraysHaveBeenInitialized; + + if (!stIsSetup) { + IRO_Log = 0; + IRO_SetupDump(); + if (!ENodeArraysHaveBeenInitialized) { + IRO_InitializeNodeNamesArray(); + IRO_InitializeIsAssociativeENodeTypeArray(); + IRO_InitializeIsSubableOpArray(); + IRO_InitializeAssignmentOpArray(); + IRO_InitializeComplementaryOpArray(); + IRO_InitializeComplementaryOpLogicalArray(); + IRO_InitializeNonAssignmentOpArray(); + IRO_InitializeAssignmentFoldingFunctionArray(); + IRO_InitializeIRO_IsModifyOpArray(); + IRO_InitializeIRO_IsAssignOpArray(); + ENodeArraysHaveBeenInitialized = 1; + } + stIsSetup = 1; + } +} + +void IRO_Cleanup(void) { + if (stIsSetup) { + IRO_CleanupDump(); + stIsSetup = 0; + } +} + +void CodeGen_UpdateOptimizerOptions(void) { + Boolean flag; + + flag = copts.optimizationlevel >= 1; + copts.deadcode = flag; + + flag = copts.optimizationlevel >= 2; + copts.propagation = flag; + copts.commonsubs = flag; + + flag = copts.optimizationlevel >= 3; + copts.vectorizeloops = flag; + copts.unrolling = flag; + copts.deadstore = flag; + copts.lifetimes = flag; + copts.strengthreduction = flag; + copts.loopinvariants = flag; + + flag = copts.optimizationlevel >= 4; + copts.multiplepasses = flag; +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.h b/compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.h new file mode 100644 index 0000000..287e279 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.h @@ -0,0 +1,30 @@ +#ifndef COMPILER_IROPTIMIZER_H +#define COMPILER_IROPTIMIZER_H + +#include "compiler/common.h" + +typedef struct IROAddrRecord IROAddrRecord; +typedef struct IROAssign IROAssign; +typedef struct IRODef IRODef; +typedef struct IROElmList IROElmList; +typedef struct IROExpr IROExpr; +typedef struct IROLinear IROLinear; +typedef struct IROList IROList; +typedef struct IROListNode IROListNode; +typedef struct IROLoop IROLoop; +typedef struct IRONode IRONode; +typedef struct IROUse IROUse; + +extern Boolean DoScalarize; +extern Boolean DoLinearize; +extern Boolean EarlyReturn; +extern Boolean IRO_CPFirstTime; +extern Boolean VectorPhaseCalledFromUnroll; +extern Boolean IRO_Log; + +extern Statement *IRO_Optimizer(Object *func, Statement *statements); +extern void IRO_Setup(void); +extern void IRO_Cleanup(void); +extern void CodeGen_UpdateOptimizerOptions(void); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroBitVect.c b/compiler_and_linker/FrontEnd/Optimizer/IroBitVect.c new file mode 100644 index 0000000..873b1ca --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroBitVect.c @@ -0,0 +1,112 @@ +#include "BitVector.h" +#include "compiler/CompilerTools.h" + +void Bv_AllocVector(BitVector **bv, UInt32 size) { + UInt32 long_size = (size / 32) + 1; + *bv = oalloc(sizeof(BitVector) + sizeof(UInt32) * long_size); + (*bv)->size = long_size; + Bv_Clear(*bv); +} + +void Bv_AllocVectorLocal(BitVector **bv, UInt32 size) { + UInt32 long_size = (size / 32) + 1; + *bv = lalloc(sizeof(BitVector) + sizeof(UInt32) * long_size); + (*bv)->size = long_size; + Bv_Clear(*bv); +} + +void Bv_ClearBit(UInt32 bit, BitVector *bv) { + if ((bit / 32) < bv->size) + bv->data[bit / 32] &= ~(1 << (bit & 31)); + else + CError_FATAL(73); +} + +void Bv_And(const BitVector *a, BitVector *b) { + UInt32 i; + for (i = 0; i < b->size; i++) + b->data[i] &= a->data[i]; +} + +void Bv_Or(const BitVector *a, BitVector *b) { + UInt32 i, len; + + len = a->size; + if (b->size < len) + len = b->size; + + for (i = 0; i < len; i++) { + b->data[i] |= a->data[i]; + } +} + +Boolean Bv_BitsInCommon(const BitVector *a, const BitVector *b) { + UInt32 len; + UInt32 i; + + len = a->size; + if (b->size < len) + len = b->size; + + for (i = 0; i < len; i++) { + if (a->data[i] & b->data[i]) + return 1; + } + + return 0; +} + +Boolean Bv_Compare(const BitVector *a, const BitVector *b) { + UInt32 i; + for (i = 0; i < a->size; i++) { + if (a->data[i] != b->data[i]) + return 0; + } + + return 1; +} + +void Bv_Minus(const BitVector *a, BitVector *b) { + UInt32 i; + for (i = 0; i < b->size; i++) + b->data[i] &= ~a->data[i]; +} + +void Bv_Copy(const BitVector *src, BitVector *dst) { + memcpy(dst->data, src->data, sizeof(UInt32) * dst->size); +} + +void Bv_Clear(BitVector *bv) { + memset(bv->data, 0, sizeof(UInt32) * bv->size); +} + +void Bv_Set(BitVector *bv) { + memset(bv->data, 0xFF, sizeof(UInt32) * bv->size); +} + +Boolean Bv_IsSubset(const BitVector *a, const BitVector *b) { + UInt32 i; + + for (i = 0; i < a->size; i++) { + if (b->size < i) { + if (a->data[i]) + return 0; + } else { + if (a->data[i] & ~(b->data[i])) + return 0; + } + } + + return 1; +} + +Boolean Bv_IsEmpty(const BitVector *bv) { + UInt32 i; + + for (i = 0; i < bv->size; i++) { + if (bv->data[i]) + return 0; + } + + return 1; +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroCSE.c b/compiler_and_linker/FrontEnd/Optimizer/IroCSE.c new file mode 100644 index 0000000..7bc4866 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroCSE.c @@ -0,0 +1,1038 @@ +#include "IroCSE.h" +#include "IroDump.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroMalloc.h" +#include "IroPointerAnalysis.h" +#include "IroSubable.h" +#include "IROUseDef.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CInt64.h" +#include "compiler/CParser.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" + +BitVector *IRO_Depends; +Boolean IRO_NotSubable; +Boolean IRO_IsVolatile; +Boolean IRO_CouldError; +IROExpr *IRO_FirstExpr; +IROExpr *IRO_LastExpr; +SInt32 IRO_NumExprs; +static Boolean HasVectorOperand; + +// forward decls +static void IRO_DependsOnForDataFlow(IROLinear *linear, Boolean flag); + +static void GetDependsOfIndirect(IROLinear *nd) { + IROListNode *resultList; + IROListNode *next; + IROListNode *list; + IROListNode *scan; + IROLinear *scannd; + Object *obj; + VarRecord *var; + int index; + Boolean result; + Boolean foundObjRef; + + result = 0; + + if (nd && copts.opt_pointer_analysis && nd->pointsToFunction && FunctionName) { + resultList = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, nd, &resultList); + if ((list = resultList)) { + for (scan = list; scan; scan = scan->nextList) { + if (!scan->list.head || !scan->list.tail) { + result = 1; + break; + } + + foundObjRef = 0; + for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) { + if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) { + foundObjRef = 1; + break; + } + } + + if (!foundObjRef) { + result = 1; + break; + } + } + + if (!result) { + while (list) { + for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) { + if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) { + obj = scannd->u.node->data.objref; + CError_ASSERT(119, obj != NULL); + var = IRO_FindVar(obj, 1, 1); + CError_ASSERT(121, var != NULL); + index = var->index; + CError_ASSERT(123, index != 0); + + if (is_volatile_object(obj)) { + IRO_IsVolatile = 1; + IRO_NotSubable = 1; + } + Bv_SetBit(index, IRO_Depends); + } + } + list = list->nextList; + } + } + + while (resultList) { + next = resultList->nextList; + IRO_free(resultList); + resultList = next; + } + } else { + result = 1; + } + } else { + result = 1; + } + + if (result) { + nd = nd->u.monadic; + if (nd->type == IROLinearOp1Arg && nd->nodetype == EBITFIELD) + nd = nd->u.monadic; + + if (nd->type == IROLinearOp2Arg && nd->nodetype == EADD) { + IRO_BaseTerms = 0; + IRO_VarTerms = 0; + IRO_DecomposeAddressExpression_Cheap(nd); + if (IRO_BaseTerms != 1) { + IRO_CouldError = 1; + Bv_SetBit(0, IRO_Depends); + Bv_Or(IRO_FuncKills, IRO_Depends); + } + if (IRO_VarTerms) + IRO_CouldError = 1; + } else { + IRO_CouldError = 1; + Bv_SetBit(0, IRO_Depends); + Bv_Or(IRO_FuncKills, IRO_Depends); + } + } +} + +static void GetDependsOfFunctionCallForDataFlow(IROLinear *nd) { + IROLinear *innernd; + IROListNode *resultList; + IROListNode *next; + IROListNode *list; + IROListNode *scan; + IROLinear *scannd; + Object *obj; + VarRecord *var; + int index; + Boolean result; + Boolean foundObjRef; + ObjectList *olist; + ObjectList *depsList; + + result = 0; + innernd = nd->u.funccall.linear8; + + if (innernd && copts.opt_pointer_analysis && innernd->pointsToFunction && FunctionName) { + resultList = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, innernd, &resultList); + if ((list = resultList)) { + for (scan = list; scan; scan = scan->nextList) { + if (!scan->list.head || !scan->list.tail) { + result = 1; + break; + } + + foundObjRef = 0; + for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) { + if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) { + foundObjRef = 1; + obj = scannd->u.node->data.objref; + CError_ASSERT(234, obj != NULL); + + depsList = NULL; + PointerAnalysis_GetFunctionDependencies(obj, nd, &depsList); + + for (olist = depsList; olist; olist = olist->next) { + if (!olist->object) { + result = 1; + break; + } + } + + while (depsList) { + olist = depsList->next; + IRO_free(depsList); + depsList = olist; + } + + if (result) + break; + } + } + + if (!foundObjRef) + result = 1; + if (result) + break; + } + + if (!result) { + for (list = resultList; list; list = list->nextList) { + for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) { + if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) { + obj = scannd->u.node->data.objref; + + depsList = NULL; + PointerAnalysis_GetFunctionDependencies(obj, nd, &depsList); + + for (olist = depsList; olist; olist = olist->next) { + var = IRO_FindVar(olist->object, 1, 1); + CError_ASSERT(285, var != NULL); + index = var->index; + CError_ASSERT(287, index != 0); + + if (is_volatile_object(olist->object)) { + IRO_IsVolatile = 1; + IRO_NotSubable = 1; + } + Bv_SetBit(index, IRO_Depends); + } + + while (depsList) { + olist = depsList->next; + IRO_free(depsList); + depsList = olist; + } + } + } + } + } + + while (resultList) { + next = resultList->nextList; + IRO_free(resultList); + resultList = next; + } + } else { + result = 1; + } + } else { + result = 1; + } + + if (result) { + IRO_DependsOnForDataFlow(nd->u.funccall.linear8, 0); + Bv_Or(IRO_FuncKills, IRO_Depends); + + for (index = nd->u.funccall.argCount - 1; index >= 0; index--) + IRO_DependsOnForDataFlow(nd->u.funccall.args[index], 0); + } +} + +static void IRO_DependsOn(IROLinear *linear, Boolean flag) { + VarRecord *var; + IROLinear *inner; + + if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) { + IRO_IsVolatile = 1; + IRO_NotSubable = 1; + } + + if (!IRO_NotSubable) { + switch (linear->type) { + case IROLinearOperand: + if (flag && linear->u.node->type == EOBJREF) { + if ((var = IRO_FindVar(linear->u.node->data.objref, 0, 1))) { + if (is_volatile_object(var->object)) { + IRO_IsVolatile = 1; + IRO_NotSubable = 1; + } + Bv_SetBit(var->index, IRO_Depends); + } else { + IRO_NotSubable = 1; + } + } + break; + case IROLinearOp1Arg: + if (IRO_IsAssignOp[linear->nodetype]) { + IRO_NotSubable = 1; + } else { + inner = linear->u.monadic; + if (linear->nodetype == EINDIRECT) { + if (inner->type == IROLinearOp1Arg && inner->nodetype == EBITFIELD) + inner = inner->u.monadic; + if (inner->type != IROLinearOperand || inner->u.node->type != EOBJREF) + GetDependsOfIndirect(linear); + } + + IRO_DependsOn(inner, linear->nodetype == EINDIRECT); + } + break; + case IROLinearOp2Arg: + if (IRO_IsAssignOp[linear->nodetype]) { + IRO_NotSubable = 1; + } else { + if (linear->nodetype == EDIV || linear->nodetype == EMODULO) { + if (IRO_IsIntConstant(linear->u.diadic.right)) { + if (CInt64_Equal(linear->u.diadic.right->u.node->data.intval, cint64_zero)) + IRO_CouldError = 1; + } else { + IRO_CouldError = 1; + } + } + + IRO_DependsOn(linear->u.diadic.left, flag); + IRO_DependsOn(linear->u.diadic.right, flag); + } + break; + case IROLinearOp3Arg: + if (IRO_IsAssignOp[linear->nodetype]) { + IRO_NotSubable = 1; + } else { + IRO_DependsOn(linear->u.args3.a, flag); + IRO_DependsOn(linear->u.args3.b, flag); + IRO_DependsOn(linear->u.args3.c, flag); + } + break; + case IROLinearFunccall: + IRO_NotSubable = 1; + break; + default: + CError_FATAL(479); + } + } +} + +static void IRO_DependsOnForDataFlow(IROLinear *linear, Boolean flag) { + VarRecord *var; + IROLinear *inner; + + if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) { + IRO_IsVolatile = 1; + IRO_NotSubable = 1; + } + + switch (linear->type) { + case IROLinearOperand: + if (flag && linear->u.node->type == EOBJREF) { + if ((var = IRO_FindVar(linear->u.node->data.objref, 0, 1))) { + if (is_volatile_object(var->object)) { + IRO_IsVolatile = 1; + IRO_NotSubable = 1; + } + Bv_SetBit(var->index, IRO_Depends); + } else { + IRO_NotSubable = 1; + } + } + break; + case IROLinearOp1Arg: + if (IRO_IsAssignOp[linear->nodetype]) + IRO_NotSubable = 1; + + inner = linear->u.monadic; + if (linear->nodetype == EINDIRECT) { + if (inner->type == IROLinearOp1Arg && inner->nodetype == EBITFIELD) + inner = inner->u.monadic; + if (inner->type != IROLinearOperand || inner->u.node->type != EOBJREF) + GetDependsOfIndirect(linear); + } + + IRO_DependsOnForDataFlow(inner, linear->nodetype == EINDIRECT); + break; + case IROLinearOp2Arg: + if (IRO_IsAssignOp[linear->nodetype]) + IRO_NotSubable = 1; + + if (linear->nodetype == EDIV || linear->nodetype == EMODULO) { + if (IRO_IsIntConstant(linear->u.diadic.right)) { + if (CInt64_Equal(linear->u.diadic.right->u.node->data.intval, cint64_zero)) + IRO_CouldError = 1; + } else { + IRO_CouldError = 1; + } + } + + IRO_DependsOnForDataFlow(linear->u.diadic.left, flag); + IRO_DependsOnForDataFlow(linear->u.diadic.right, flag); + break; + case IROLinearOp3Arg: + if (IRO_IsAssignOp[linear->nodetype]) + IRO_NotSubable = 1; + + IRO_DependsOnForDataFlow(linear->u.args3.a, flag); + IRO_DependsOnForDataFlow(linear->u.args3.b, flag); + IRO_DependsOnForDataFlow(linear->u.args3.c, flag); + break; + case IROLinearFunccall: + IRO_NotSubable = 1; + GetDependsOfFunctionCallForDataFlow(linear); + break; + default: + CError_FATAL(650); + } +} + +void IRO_FindDepends_NoAlloc(IROLinear *linear) { + Bv_Clear(IRO_Depends); + IRO_CouldError = 0; + IRO_NotSubable = 0; + IRO_IsVolatile = 0; + IRO_DependsOnForDataFlow(linear, 0); +} + +void IRO_FindDepends(IROLinear *linear) { + Bv_AllocVector(&IRO_Depends, IRO_NumVars + 1); + IRO_CouldError = 0; + IRO_NotSubable = 0; + IRO_DependsOn(linear, 0); +} + +static void VecAct(IROLinear *linear, Boolean isFirst) { + if (!isFirst && (linear->flags & IROLF_VecOpBase)) + HasVectorOperand = 1; +} + +static Boolean IRO_DoesNotHaveVectorOperand(IROLinear *linear) { + HasVectorOperand = 0; + IRO_WalkTree(linear, VecAct); + return HasVectorOperand == 0; +} + +static void IRO_AddExpression(IROLinear *linear, IRONode *node, Boolean flag) { + IROExpr *expr; + + if ((linear->flags & IROLF_Reffed) && IRO_IsSubableExpression(linear) && IRO_DoesNotHaveVectorOperand(linear)) { + expr = oalloc(sizeof(IROExpr)); + expr->x0 = 0; + expr->index = ++IRO_NumExprs; + expr->linear = linear; + expr->x8 = NULL; + expr->node = node; + IRO_FindDepends(linear); + expr->depends = IRO_Depends; + expr->notSubable = IRO_NotSubable; + expr->couldError = IRO_CouldError; + expr->next = NULL; + expr->x14 = NULL; + if (IRO_FirstExpr) + IRO_LastExpr->next = expr; + else + IRO_FirstExpr = expr; + IRO_LastExpr = expr; + linear->expr = expr; + } +} + +void IRO_FindExpressions(BitVector *bv, Boolean flag) { + IROLinear *nd; + IRONode *fnode; + + IRO_FirstExpr = IRO_LastExpr = NULL; + IRO_NumExprs = 0; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (!bv || Bv_IsBitSet(fnode->index, bv)) { + for (nd = fnode->first; nd; nd = nd->next) { + nd->expr = NULL; + IRO_AddExpression(nd, fnode, flag); + if (nd == fnode->last) + break; + } + } else { + for (nd = fnode->first; nd; nd = nd->next) { + nd->expr = NULL; + if (nd == fnode->last) + break; + } + } + } + + IRO_CheckForUserBreak(); +} + +void IRO_RemoveExpr(IROExpr *expr) { + IROExpr *prev; + IROExpr *scan; + + scan = IRO_FirstExpr; + prev = NULL; + while (scan != expr) { + prev = scan; + scan = scan->next; + CError_ASSERT(809, scan); + } + + expr->linear->expr = NULL; + if (prev) + prev->next = expr->next; + else + IRO_FirstExpr = expr->next; +} + +static void GetExprKillsByIndirectAssignment(IROLinear *linear) { + IROLinear *inner; + IROListNode *resultList; + IROListNode *next; + IROListNode *list; + IROListNode *scan; + IROLinear *scannd; + Object *obj; + VarRecord *var; + int index; + Boolean result; + Boolean foundObjRef; + IROExpr *expr; + + result = 0; + if (linear->type == IROLinearOp2Arg) + linear = linear->u.diadic.left; + else + linear = linear->u.monadic; + + if ( + linear && + linear->type == IROLinearOp1Arg && + linear->nodetype == EINDIRECT && + (inner = linear->u.monadic) && + copts.opt_pointer_analysis && + inner->pointsToFunction && + FunctionName + ) { + resultList = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, inner, &resultList); + if ((list = resultList)) { + for (scan = list; scan; scan = scan->nextList) { + if (!scan->list.head || !scan->list.tail) { + result = 1; + break; + } + + foundObjRef = 0; + for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) { + if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) { + foundObjRef = 1; + break; + } + } + + if (!foundObjRef) { + result = 1; + break; + } + } + + if (!result) { + while (list) { + for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) { + if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) { + obj = scannd->u.node->data.objref; + CError_ASSERT(893, obj != NULL); + var = IRO_FindVar(obj, 1, 1); + CError_ASSERT(895, var != NULL); + index = var->index; + + for (expr = IRO_FirstExpr; expr; expr = expr->next) { + if (Bv_IsBitSet(index, expr->depends)) + Bv_SetBit(expr->index, IRO_ExprKills); + } + } + } + list = list->nextList; + } + } + + while (resultList) { + next = resultList->nextList; + IRO_free(resultList); + resultList = next; + } + } else { + result = 1; + } + } else { + result = 1; + } + + if (result) { + for (expr = IRO_FirstExpr; expr; expr = expr->next) { + if (Bv_BitsInCommon(expr->depends, IRO_FuncKills)) + Bv_SetBit(expr->index, IRO_ExprKills); + } + } +} + +static void GetExprKillsByFunctionCall(IROLinear *funccall) { + IROLinear *innernd; + IROListNode *resultList; + IROListNode *next; + IROListNode *list; + IROListNode *scan; + IROLinear *scannd; + Object *obj; + VarRecord *var; + int index; + Boolean result; + Boolean foundObjRef; + ObjectList *olist; + ObjectList *depsList; + IROExpr *expr; + + result = 0; + innernd = funccall->u.funccall.linear8; + + if (innernd && copts.opt_pointer_analysis && innernd->pointsToFunction && FunctionName) { + resultList = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, innernd, &resultList); + if ((list = resultList)) { + for (scan = list; scan; scan = scan->nextList) { + if (!scan->list.head || !scan->list.tail) { + result = 1; + break; + } + + foundObjRef = 0; + for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) { + if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) { + foundObjRef = 1; + obj = scannd->u.node->data.objref; + CError_ASSERT(991, obj != NULL); + + depsList = NULL; + PointerAnalysis_GetFunctionKills(obj, funccall, &depsList); + + for (olist = depsList; olist; olist = olist->next) { + if (!olist->object) { + result = 1; + break; + } + } + + while (depsList) { + olist = depsList->next; + IRO_free(depsList); + depsList = olist; + } + + if (result) + break; + } + } + + if (!foundObjRef) + result = 1; + if (result) + break; + } + + if (!result) { + for (list = resultList; list; list = list->nextList) { + for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) { + if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) { + obj = scannd->u.node->data.objref; + + depsList = NULL; + PointerAnalysis_GetFunctionKills(obj, funccall, &depsList); + + for (olist = depsList; olist; olist = olist->next) { + var = IRO_FindVar(olist->object, 1, 1); + CError_ASSERT(1042, var != NULL); + index = var->index; + CError_ASSERT(1044, index != 0); + + for (expr = IRO_FirstExpr; expr; expr = expr->next) { + if (Bv_IsBitSet(index, expr->depends)) + Bv_SetBit(expr->index, IRO_ExprKills); + } + } + + while (depsList) { + olist = depsList->next; + IRO_free(depsList); + depsList = olist; + } + } + } + } + } + + while (resultList) { + next = resultList->nextList; + IRO_free(resultList); + resultList = next; + } + } else { + result = 1; + } + } else { + result = 1; + } + + if (result) { + for (expr = IRO_FirstExpr; expr; expr = expr->next) { + if (Bv_BitsInCommon(expr->depends, IRO_FuncKills)) + Bv_SetBit(expr->index, IRO_ExprKills); + } + } +} + +static void IRO_GetExprKills(IROLinear *linear) { + Bv_Clear(IRO_ExprKills); + switch (linear->type) { + case IROLinearOp1Arg: + case IROLinearOp2Arg: + if (IRO_IsAssignOp[linear->nodetype]) { + VarRecord *var; + int index; + + var = IRO_FindAssigned(linear); + index = 0; + if (var) + index = var->index; + if (!index) { + GetExprKillsByIndirectAssignment(linear); + } else { + IROExpr *expr; + for (expr = IRO_FirstExpr; expr; expr = expr->next) { + if (Bv_IsBitSet(index, expr->depends)) + Bv_SetBit(expr->index, IRO_ExprKills); + } + } + } + break; + case IROLinearAsm: { + IROExpr *expr; + IRO_GetKills(linear); + for (expr = IRO_FirstExpr; expr; expr = expr->next) { + if (Bv_BitsInCommon(expr->depends, IRO_VarKills)) + Bv_SetBit(expr->index, IRO_ExprKills); + } + break; + } + case IROLinearFunccall: + GetExprKillsByFunctionCall(linear); + break; + } +} + +void IRO_ComputeAvail(void) { + IRONode *node; + IROLinear *linear; + SInt32 counter; + BitVector *bv; + Boolean flag; + + counter = 0; + node = IRO_FirstNode; + Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1); + Bv_AllocVector(&IRO_ExprKills, IRO_NumExprs + 1); + + while (node) { + Bv_AllocVector(&node->x16, IRO_NumExprs); + if (node->numpred) + Bv_Set(node->x16); + Bv_AllocVector(&node->x22, IRO_NumExprs); + Bv_AllocVector(&node->x1E, IRO_NumExprs); + Bv_AllocVector(&node->x1A, IRO_NumExprs); + + for (linear = node->first; linear; linear = linear->next) { + if (linear->expr) + Bv_SetBit(linear->expr->index, node->x1E); + IRO_GetExprKills(linear); + Bv_Or(IRO_ExprKills, node->x22); + Bv_Minus(IRO_ExprKills, node->x1E); + if (linear == node->last) + break; + + if (counter > 250) { + IRO_CheckForUserBreak(); + counter = 0; + } else { + counter++; + } + } + + Bv_Copy(node->x16, node->x1A); + Bv_Minus(node->x22, node->x1A); + Bv_Or(node->x1E, node->x1A); + node = node->nextnode; + } + + IRO_CheckForUserBreak(); + + Bv_AllocVector(&bv, IRO_NumExprs); + do { + flag = 0; + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (!node->numpred) { + Bv_Clear(bv); + } else { + UInt16 i; + Bv_Set(bv); + for (i = 0; i < node->numpred; i++) + Bv_And(IRO_NodeTable[node->pred[i]]->x1A, bv); + } + + if (!Bv_Compare(bv, node->x16)) { + flag = 1; + Bv_Copy(bv, node->x16); + } + + Bv_Copy(node->x16, node->x1A); + Bv_Minus(node->x22, node->x1A); + Bv_Or(node->x1E, node->x1A); + } + IRO_CheckForUserBreak(); + } while (flag); +} + +static void IRO_MakeReplacementEmbedded(IROExpr *expr) { + IROLinear *opnd; + IROLinear *ind; + IROLinear *ass; + + IRO_GetTemp(expr); + + opnd = IRO_NewLinear(IROLinearOperand); + opnd->u.node = create_objectrefnode(expr->x8); + opnd->rtype = opnd->u.node->data.objref->type; + opnd->index = ++IRO_NumLinear; + opnd->flags |= IROLF_Reffed | IROLF_Assigned | IROLF_Ind; + + ind = IRO_NewLinear(IROLinearOp1Arg); + ind->nodetype = EINDIRECT; + ind->rtype = expr->linear->rtype; + ind->u.monadic = opnd; + ind->index = ++IRO_NumLinear; + ind->flags |= IROLF_Reffed | IROLF_Assigned; + + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->nodetype = EASS; + ass->u.diadic.left = ind; + ass->u.diadic.right = expr->linear; + ass->rtype = expr->linear->rtype; + ass->index = ++IRO_NumLinear; + + opnd->next = ind; + ind->next = ass; + IRO_ReplaceReferenceWithNode(expr->linear, ass); + IRO_PasteAfter(opnd, ass, expr->linear); +} + +static void IRO_ActUnmarkSubExpressions(IROLinear *linear, Boolean isFirst) { + if (isFirst) + linear->flags &= ~IROLF_8; +} + +static void CheckCommonSub(IROLinear *linear) { + IROExpr *expr; + + for (expr = IRO_FirstExpr; expr; expr = expr->next) { + if (expr->linear != linear && !expr->x14) { + if (Bv_IsBitSet(expr->index, IRO_Avail) && !expr->notSubable && IRO_ExprsSame(linear, expr->linear)) { + IRO_WalkTree(linear, IRO_ActUnmarkSubExpressions); + linear->flags |= IROLF_8; + linear->expr->x14 = expr; + break; + } + } + } +} + +static void MoveCommonSub(IROExpr *expr) { + SInt32 best; + SInt32 sz1; + SInt32 sz2; + SInt32 i1; + SInt32 i2; + IROLinear *scan; + IROLinear *array1[64]; + IROLinear *array2[64]; + IROExpr *scanexpr; + + sz1 = 0; + scan = expr->linear; + do { + scan = IRO_LocateFather(scan); + if (scan) { + if (sz1 == 64) + return; + array1[sz1++] = scan; + } + } while (scan); + + best = -1; + for (scanexpr = IRO_FirstExpr; scanexpr; scanexpr = scanexpr->next) { + if (scanexpr->x14 == expr) { + sz2 = 0; + scan = scanexpr->linear; + do { + scan = IRO_LocateFather(scan); + if (scan) { + if (sz2 == 64) + return; + array2[sz2++] = scan; + } + } while (scan); + + i1 = sz1; + i2 = sz2; + while (i1 && i2 && array1[i1 - 1] == array2[i2 - 1]) { + i1--; + i2--; + } + + if (i1 != sz1 && i1 > best) + best = i1; + } + } + + if (best < 0) { + IRO_MakeReplacementEmbedded(expr); + } else { + IROLinear *start; + IROLinear *comma; + IRO_Dump("Moving common sub from node %d to %d\n", expr->linear->index, array1[best]->index); + start = IRO_FindStart(array1[best]); + IRO_GetTemp(expr); + IRO_ReplaceReference(expr->linear, expr->x8, expr->linear); + IRO_MoveExpression(expr, start); + + comma = IRO_NewLinear(IROLinearOp2Arg); + comma->nodetype = ECOMMA; + comma->rtype = array1[best]->rtype; + comma->u.diadic.left = IRO_AssignToTemp(expr); + comma->u.diadic.right = array1[best]; + comma->stmt = array1[best]->stmt; + IRO_ReplaceReferenceWithNode(array1[best], comma); + IRO_PasteAfter(comma, comma, array1[best]); + } +} + +static void ReplaceCommonSub(IROLinear *linear) { + IROExpr *expr = linear->expr->x14; + if (!expr->x8) { + MoveCommonSub(expr); + if (!expr->x8) + return; + } + + IRO_Dump("Replacing common sub at %d with %d\n", linear->index, expr->linear->index); + IRO_ReplaceReference(linear, expr->x8, linear); + IRO_RemoveExpr(linear->expr); + IRO_NopOut(linear); +} + +void IRO_CommonSubs(void) { + IRONode *node; + IROLinear *linear; + SInt32 counter; + + counter = 0; + for (node = IRO_FirstNode; node; node = node->nextnode) { + IRO_Avail = node->x16; + linear = node->first; + while (1) { + if (!linear) + break; + if (linear->expr && !linear->expr->notSubable) + CheckCommonSub(linear); + if (linear->expr) + Bv_SetBit(linear->expr->index, IRO_Avail); + IRO_GetExprKills(linear); + Bv_Minus(IRO_ExprKills, IRO_Avail); + if (linear == node->last) + break; + if (counter > 250) { + IRO_CheckForUserBreak(); + counter = 0; + } else { + counter++; + } + linear = linear->next; + } + } + + for (node = IRO_FirstNode; node; node = node->nextnode) { + for (linear = node->first; linear; linear = linear->next) { + if (linear->expr && (linear->flags & IROLF_8) && !IRO_HasSideEffect(linear)) + ReplaceCommonSub(linear); + if (linear == node->last) + break; + if (counter > 250) { + IRO_CheckForUserBreak(); + counter = 0; + } else { + counter++; + } + } + } + + IRO_CheckForUserBreak(); +} + +static Boolean CountThisSubableOperandUse(IROUse *use) { + return use->x1C != 0; +} + +static int GetSubableOperandUseCount(VarRecord *var) { + int count = 0; + IROUse *use; + + if (var->uses) { + for (use = var->uses; use; use = use->varnext) { + if (CountThisSubableOperandUse(use)) + count++; + } + } + + return count; +} + +static void IRO_MakeTopLevelExprForSubableOperand(IROLinear *linear) { + IROLinear *copy = IRO_NewLinear(IROLinearOperand); + memcpy(copy, linear, sizeof(IROLinear)); + copy->index = ++IRO_NumLinear; + + if (IRO_FirstLinear && IRO_FirstLinear->type == IROLinearNop) + IRO_PasteAfter(copy, copy, IRO_FirstLinear); + else + IRO_Paste(copy, copy, IRO_FirstLinear); +} + +void IRO_GenerateTopLevelExprsForSubableOperands(void) { + IROLinear *nd; + IRONode *fnode; + VarRecord *var; + BitVector *bv; + + Bv_AllocVector(&bv, IRO_NumVars + 1); + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + for (nd = fnode->first; nd; nd = nd->next) { + nd->expr = NULL; + if ((nd->flags & IROLF_Reffed) && IRO_IsSubableExpression(nd) && IRO_DoesNotHaveVectorOperand(nd)) { + if (nd->type == IROLinearOperand && nd->u.node && nd->u.node->type == EOBJREF) { + if ((var = IRO_FindVar(nd->u.node->data.objref, 0, 1))) { + if (!Bv_IsBitSet(var->index, bv)) { + IRO_MakeTopLevelExprForSubableOperand(nd); + Bv_SetBit(var->index, bv); + } + } + } + } + + if (nd == fnode->last) + break; + } + } +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroCSE.h b/compiler_and_linker/FrontEnd/Optimizer/IroCSE.h new file mode 100644 index 0000000..c1e166c --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroCSE.h @@ -0,0 +1,45 @@ +#ifndef COMPILER_IROCSE_H +#define COMPILER_IROCSE_H + +#include "IrOptimizer.h" +#include "BitVector.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +struct IROExpr { + Boolean x0; + UInt16 index; + IROLinear *linear; + Object *x8; + IRONode *node; + BitVector *depends; + IROExpr *x14; + Boolean couldError; + Boolean notSubable; + IROLinear *x1A; + VarRecord *x1E; + IROLinear *x22; + IROExpr *next; +}; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +extern BitVector *IRO_Depends; +extern Boolean IRO_NotSubable; +extern Boolean IRO_IsVolatile; +extern Boolean IRO_CouldError; +extern IROExpr *IRO_FirstExpr; +extern IROExpr *IRO_LastExpr; +extern SInt32 IRO_NumExprs; + +extern void IRO_FindDepends_NoAlloc(IROLinear *linear); +extern void IRO_FindDepends(IROLinear *linear); +extern void IRO_FindExpressions(BitVector *bv, Boolean flag); +extern void IRO_RemoveExpr(IROExpr *expr); +extern void IRO_ComputeAvail(void); +extern void IRO_CommonSubs(void); +extern void IRO_GenerateTopLevelExprsForSubableOperands(void); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroDump.c b/compiler_and_linker/FrontEnd/Optimizer/IroDump.c new file mode 100644 index 0000000..d21496f --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroDump.c @@ -0,0 +1,660 @@ +#include "IroDump.h" +#include "IroCSE.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroPropagate.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/CFunc.h" +#include "compiler/CInt64.h" +#include "compiler/CParser.h" +#include "compiler/objects.h" + +static FILE *DumpFile; +static char *nodenames[MAXEXPR]; + +char *IRO_NodeName(ENodeType nodetype) { + return nodenames[nodetype]; +} + +void IRO_InitializeNodeNamesArray(void) { + int i; + for (i = 0; i < MAXEXPR; i++) + nodenames[i] = ""; + + nodenames[EPOSTINC] = "EPOSTINC"; + nodenames[EPOSTDEC] = "EPOSTDEC"; + nodenames[EPREINC] = "EPREINC"; + nodenames[EPREDEC] = "EPREDEC"; + nodenames[EINDIRECT] = "EINDIRECT"; + nodenames[EMONMIN] = "EMONMIN"; + nodenames[EBINNOT] = "EBINNOT"; + nodenames[ELOGNOT] = "ELOGNOT"; + nodenames[EFORCELOAD] = "EFORCELOAD"; + nodenames[EMUL] = "EMUL"; + nodenames[EMULV] = "EMULV"; + nodenames[EDIV] = "EDIV"; + nodenames[EMODULO] = "EMODULO"; + nodenames[EADDV] = "EADDV"; + nodenames[ESUBV] = "ESUBV"; + nodenames[EADD] = "EADD"; + nodenames[ESUB] = "ESUB"; + nodenames[ESHL] = "ESHL"; + nodenames[ESHR] = "ESHR"; + nodenames[ELESS] = "ELESS"; + nodenames[EGREATER] = "EGREATER"; + nodenames[ELESSEQU] = "ELESSEQU"; + nodenames[EGREATEREQU] = "EGREATEREQU"; + nodenames[EEQU] = "EEQU"; + nodenames[ENOTEQU] = "ENOTEQU"; + nodenames[EAND] = "EAND"; + nodenames[EXOR] = "EXOR"; + nodenames[EOR] = "EOR"; + nodenames[ELAND] = "ELAND"; + nodenames[ELOR] = "ELOR"; + nodenames[EASS] = "EASS"; + nodenames[EMULASS] = "EMULASS"; + nodenames[EDIVASS] = "EDIVASS"; + nodenames[EMODASS] = "EMODASS"; + nodenames[EADDASS] = "EADDASS"; + nodenames[ESUBASS] = "ESUBASS"; + nodenames[ESHLASS] = "ESHLASS"; + nodenames[ESHRASS] = "ESHRASS"; + nodenames[EANDASS] = "EANDASS"; + nodenames[EXORASS] = "EXORASS"; + nodenames[EORASS] = "EORASS"; + nodenames[ECOMMA] = "ECOMMA"; + nodenames[EPMODULO] = "EPMODULO"; + nodenames[EROTL] = "EROTL"; + nodenames[EROTR] = "EROTR"; + nodenames[EBCLR] = "EBCLR"; + nodenames[EBTST] = "EBTST"; + nodenames[EBSET] = "EBSET"; + nodenames[ETYPCON] = "ETYPCON"; + nodenames[EBITFIELD] = "EBITFIELD"; + nodenames[EINTCONST] = "EINTCONST"; + nodenames[EFLOATCONST] = "EFLOATCONST"; + nodenames[ESTRINGCONST] = "ESTRINGCONST"; + nodenames[ECOND] = "ECOND"; + nodenames[EFUNCCALL] = "EFUNCCALL"; + nodenames[EFUNCCALLP] = "EFUNCCALLP"; + nodenames[EOBJREF] = "EOBJREF"; + nodenames[EMFPOINTER] = "EMFPOINTER"; + nodenames[ENULLCHECK] = "ENULLCHECK"; + nodenames[EPRECOMP] = "EPRECOMP"; + nodenames[ETEMP] = "ETEMP"; + nodenames[EARGOBJ] = "EARGOBJ"; + nodenames[ELOCOBJ] = "ELOCOBJ"; + nodenames[ELABEL] = "ELABEL"; + nodenames[ESETCONST] = "ESETCONST"; + nodenames[ENEWEXCEPTION] = "ENEWEXCEPTION"; + nodenames[ENEWEXCEPTIONARRAY] = "ENEWEXCEPTIONARRAY"; + nodenames[EOBJLIST] = "EOBJLIST"; + nodenames[EMEMBER] = "EMEMBER"; + nodenames[ETEMPLDEP] = "ETEMPLDEP"; + nodenames[EINSTRUCTION] = "EINSTRUCTION"; + nodenames[EDEFINE] = "EDEFINE"; + nodenames[EREUSE] = "EREUSE"; + nodenames[EASSBLK] = "EASSBLK"; + nodenames[EVECTOR128CONST] = "EVECTOR128CONST"; + nodenames[ECONDASS] = "ECONDASS"; +} + +static void DumpENode(ENode *enode) { + char buf[64]; + + if (IRO_Log) { + switch (enode->type) { + case EOBJREF: + fprintf(DumpFile, "%s", enode->data.objref->name->name); + break; + case EINTCONST: + CInt64_PrintDec(buf, enode->data.intval); + fprintf(DumpFile, "%s", buf); + break; + case EFLOATCONST: + fprintf(DumpFile, "%g", enode->data.floatval.value); + break; + case EVECTOR128CONST: + fprintf(DumpFile, "%.8lX%.8lX%.8lX%.8lX", + enode->data.vector128val.ul[0], + enode->data.vector128val.ul[1], + enode->data.vector128val.ul[2], + enode->data.vector128val.ul[3] + ); + break; + } + } +} + +static void DumpLinearNode(IROLinear *linear) { + int i; + + if (IRO_Log) { + fprintf(DumpFile, "%4d: ", linear->index); + switch (linear->type) { + case IROLinearNop: + fprintf(DumpFile, "Nop"); + break; + case IROLinearOperand: + fprintf(DumpFile, "Operand "); + DumpENode(linear->u.node); + break; + case IROLinearOp1Arg: + fprintf(DumpFile, "%s %d", nodenames[linear->nodetype], linear->u.monadic->index); + break; + case IROLinearOp2Arg: + fprintf(DumpFile, "%s %d %d", nodenames[linear->nodetype], linear->u.diadic.left->index, linear->u.diadic.right->index); + break; + case IROLinearGoto: + fprintf(DumpFile, "Goto %s", linear->u.label.label->name->name); + break; + case IROLinearIf: + fprintf(DumpFile, "If %d %s", linear->u.label.x4->index, linear->u.label.label->name->name); + break; + case IROLinearIfNot: + fprintf(DumpFile, "IfNot %d %s", linear->u.label.x4->index, linear->u.label.label->name->name); + break; + case IROLinearReturn: + fprintf(DumpFile, "Return "); + if (linear->u.monadic) + fprintf(DumpFile, "%d", linear->u.monadic->index); + break; + case IROLinearLabel: + fprintf(DumpFile, "Label %s", linear->u.label.label->name->name); + break; + case IROLinearSwitch: + fprintf(DumpFile, "Switch %d", linear->u.swtch.x4->index); + break; + case IROLinearOp3Arg: + fprintf(DumpFile, "%s %d %d %d", + nodenames[linear->nodetype], + linear->u.args3.a->index, + linear->u.args3.b->index, + linear->u.args3.c->index); + break; + case IROLinearFunccall: + fprintf(DumpFile, "Funccall %d(", linear->u.funccall.linear8->index); + for (i = 0; i < linear->u.funccall.argCount; i++) { + fprintf(DumpFile, "%d", linear->u.funccall.args[i]->index); + if (i < (linear->u.funccall.argCount - 1)) + fprintf(DumpFile, ","); + } + fprintf(DumpFile, ")"); + break; + case IROLinearBeginCatch: + fprintf(DumpFile, "BeginCatch %d", linear->u.ctch.linear->index); + break; + case IROLinearEndCatch: + fprintf(DumpFile, "EndCatch %d", linear->u.monadic->index); + break; + case IROLinearEndCatchDtor: + fprintf(DumpFile, "EndCatchDtor %d", linear->u.monadic->index); + break; + case IROLinearEnd: + fprintf(DumpFile, "End"); + break; + } + + if (linear->flags & IROLF_Assigned) fprintf(DumpFile, " <assigned>"); + if (linear->flags & IROLF_Used) fprintf(DumpFile, " <used>"); + if (linear->flags & IROLF_Ind) fprintf(DumpFile, " <ind>"); + if (linear->flags & IROLF_Subs) fprintf(DumpFile, " <subs>"); + if (linear->flags & IROLF_LoopInvariant) fprintf(DumpFile, " <loop invariant>"); + if (linear->flags & IROLF_BeginLoop) fprintf(DumpFile, " <begin loop>"); + if (linear->flags & IROLF_EndLoop) fprintf(DumpFile, " <end loop>"); + if (linear->flags & IROLF_Ris) fprintf(DumpFile, " <ris>"); + if (linear->flags & IROLF_Immind) fprintf(DumpFile, " <immind>"); + if (linear->flags & IROLF_Reffed) fprintf(DumpFile, " <reffed>"); + if (linear->flags & IROLF_VecOp) fprintf(DumpFile, " <vec op>"); + if (linear->flags & IROLF_VecOpBase) fprintf(DumpFile, " <vec op_base>"); + if (linear->flags & IROLF_CounterLoop) fprintf(DumpFile, " <counter loop>"); + if (linear->flags & IROLF_BitfieldIndirect) fprintf(DumpFile, " <bitfield_indirect>"); + if (linear->flags & IROLF_CouldError) fprintf(DumpFile, " <could_error>"); + + if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) + fprintf(DumpFile, " <volatile>"); + + if (IS_LINEAR_ENODE(linear, EOBJREF)) { + VarRecord *var = IRO_FindVar(linear->u.node->data.objref, 0, 1); + if (var && is_volatile_object(var->object)) + fprintf(DumpFile, " <volatile obj>"); + } + + fprintf(DumpFile, "\n"); + } +} + +static void DumpAct(IROLinear *linear, Boolean isFirst) { + if (!isFirst) + DumpLinearNode(linear); +} + +void IRO_DumpIntTree(IROLinear *linear) { + IRO_WalkTree(linear, DumpAct); +} + +void IRO_DumpLinearList(IROLinear *linear) { + if (!IRO_Log) + return; + + while (linear) { + DumpLinearNode(linear); + linear = linear->next; + } + fprintf(DumpFile, "\n"); +} + +static void DumpList(int num, UInt16 *list) { + int i; + + if (IRO_Log) { + for (i = 0; i < num; i++) + fprintf(DumpFile, "%d ", list[i]); + fprintf(DumpFile, "\n"); + } +} + +void IRO_DumpBits(char *name, BitVector *bv) { + SInt32 i; + SInt32 rangeStart; + Boolean inRange = 0; + Boolean isFirst = 1; + + if (!IRO_Log) + return; + + fprintf(DumpFile, name); + if (!bv) { + fprintf(DumpFile, "NULL"); + } else { + for (i = 0; i < (bv->size * 32); i++) { + if (Bv_IsBitSet(i, bv)) { + if (!inRange) { + if (!isFirst) + fputc(',', DumpFile); + isFirst = 0; + fprintf(DumpFile, "%d", i); + inRange = 1; + rangeStart = i; + } + } else { + if (inRange) { + inRange = 0; + if (i != (rangeStart + 1)) + fprintf(DumpFile, "-%d", i - 1); + } + } + } + + if (inRange && i != (rangeStart + 1)) + fprintf(DumpFile, "-%d", i - 1); + } + + fprintf(DumpFile, "\n"); +} + +void IRO_DumpAfterPhase(char *str, Boolean flag) { +#ifdef CW_ENABLE_IRO_DEBUG + if (copts.debuglisting) + flag = 1; +#endif + if (flag) { + IRO_Dump("Dumping function %s after %s \n", FunctionName ? FunctionName->name->name : "Init-code", str); + IRO_Dump("--------------------------------------------------------------------------------\n"); + IRO_DumpFlowgraph(); + } +} + +void IRO_LogForFunction(char *name) { + if (FunctionName) { + if (!strcmp(FunctionName->name->name, name)) + IRO_Log = 1; + else + IRO_Log = 0; + } +} + +void IRO_DumpFlowgraph(void) { + IRONode *node; + IROLinear *linear; + + if (IRO_Log && DumpFile) { + fprintf(DumpFile, "\nFlowgraph\n"); + for (node = IRO_FirstNode; node; node = node->nextnode) { + fprintf(DumpFile, "Flowgraph node %d First=%d, Last=%d\n", node->index, node->first->index, node->last->index); + + fprintf(DumpFile, "Succ = "); + DumpList(node->numsucc, node->succ); + fprintf(DumpFile, "Pred = "); + DumpList(node->numpred, node->pred); + + fprintf(DumpFile, "MustReach = %d, MustReach1=%d\n", node->mustreach, node->mustreach1); + fprintf(DumpFile, "LoopDepth = %d\n", node->loopdepth); + + IRO_DumpBits("Dom: ", node->dom); + if ((linear = node->first)) { + while (1) { + DumpLinearNode(linear); + if (linear == node->last) + break; + linear = linear->next; + } + } + + fprintf(DumpFile, "\n\n"); + } + fprintf(DumpFile, "\n"); + fflush(DumpFile); + } +} + +void IRO_DumpNode(IRONode *node) { + IROLinear *linear; + + if (IRO_Log) { + if (!DumpFile) + return; + + while (node) { + fprintf(DumpFile, "Flowgraph node %d First=%d, Last=%d\n", node->index, node->first->index, + node->last->index); + + fprintf(DumpFile, "Succ = "); + DumpList(node->numsucc, node->succ); + fprintf(DumpFile, "Pred = "); + DumpList(node->numpred, node->pred); + + fprintf(DumpFile, "MustReach = %d MustReach1 = %d\n", node->mustreach, node->mustreach1); + fprintf(DumpFile, "LoopDepth = %d\n", node->loopdepth); + + IRO_DumpBits("Dom: ", node->dom); + if ((linear = node->first)) { + while (1) { + DumpLinearNode(linear); + if (linear == node->last) + break; + linear = linear->next; + } + } + + fprintf(DumpFile, "\n\n"); + node = node->nextnode; + } + + fprintf(DumpFile, "\n"); + fflush(DumpFile); + } +} + +void IRO_DumpAssignments(void) { + IROAssign *assign; + + if (IRO_Log) { + fprintf(DumpFile, "\nAssignments\n\n"); + for (assign = IRO_FirstAssign; assign; assign = assign->next) { + fprintf(DumpFile, "%5d ", assign->index); + DumpLinearNode(assign->linear); + fprintf(DumpFile, "\n"); + } + fprintf(DumpFile, "\n"); + } +} + +void IRO_DumpVars(void) { + VarRecord *var; + + if (IRO_Log) { + fprintf(DumpFile, "\nVariables\n"); + for (var = IRO_FirstVar; var; var = var->next) { + fprintf(DumpFile, "%5d %s %s\n", var->index, var->object->name->name, var->xB ? "<addressed>" : ""); + } + fprintf(DumpFile, "\n"); + } +} + +void IRO_DumpDf(void) { + IRONode *node; + + if (IRO_Log) { + for (node = IRO_FirstNode; node; node = node->nextnode) { + fprintf(DumpFile, "Node %d\n", node->index); + if (node->x16) IRO_DumpBits("In: ", node->x16); + if (node->x1E) IRO_DumpBits("Gen: ", node->x1E); + if (node->x22) IRO_DumpBits("Kill: ", node->x22); + if (node->x1A) IRO_DumpBits("Out: ", node->x1A); + if (node->x2A) IRO_DumpBits("AA: ", node->x2A); + fprintf(DumpFile, "\n"); + } + fprintf(DumpFile, "\n"); + } +} + +void IRO_DumpExprs(void) { + IROExpr *expr; + + if (IRO_Log) { + fprintf(DumpFile, "Expressions\n\n"); + for (expr = IRO_FirstExpr; expr; expr = expr->next) { + fprintf(DumpFile, "%4d: %d FN:%d CE:%d NS:%d ", expr->index, expr->linear->index, expr->node->index, expr->couldError, expr->notSubable); + IRO_DumpBits("Depends: ", expr->depends); + fprintf(DumpFile, "\n"); + } + fprintf(DumpFile, "\n"); + } +} + +void IRO_SetupDump(void) { +#ifdef CW_ENABLE_IRO_DEBUG + IRO_Log = 1; +#endif + + if (IRO_Log) { + if ((DumpFile = fopen("OPT.LOG", "wt")) == NULL) + IRO_Log = 0; + } +} + +void IRO_CleanupDump(void) { + if (DumpFile) + fclose(DumpFile); +} + +void IRO_Dump(char *format, ...) { + va_list va; + if (IRO_Log) { + va_start(va, format); + vfprintf(DumpFile, format, va); + va_end(va); + } +} + +void IRO_DumpAddr(IROAddrRecord *rec) { + IROElmList *list; + + if (IRO_Log && DumpFile) { + fprintf(DumpFile, "\n"); + fprintf(DumpFile, "Address :\n"); + IRO_DumpIntTree(rec->linear); + fprintf(DumpFile, "\n"); + fprintf(DumpFile, "BaseTerms:\n"); + for (list = rec->objRefs; list; list = list->next) { + IRO_DumpIntTree(list->element); + fprintf(DumpFile, "\n"); + } + fprintf(DumpFile, "VarTerms:\n"); + for (list = rec->misc; list; list = list->next) { + IRO_DumpIntTree(list->element); + fprintf(DumpFile, "\n"); + } + fprintf(DumpFile, "ConstTerms:\n"); + for (list = rec->ints; list; list = list->next) { + IRO_DumpIntTree(list->element); + fprintf(DumpFile, "\n"); + } + } +} + +static void IRO_DumpType(Type *type) { + char buf[256]; + IRO_SpellType(type, buf); + fprintf(DumpFile, " (%s)", buf); +} + +void IRO_SpellType(Type *type, char *buf) { + char mybuf[256]; + char mybuf2[256]; + + switch (type->type) { + case TYPEVOID: + strcpy(buf, "void"); + break; + case TYPEINT: + switch (TYPE_INTEGRAL(type)->integral) { + case IT_BOOL: + strcpy(buf, "bool"); + break; + case IT_CHAR: + strcpy(buf, "char"); + break; + case IT_WCHAR_T: + strcpy(buf, "wchar_t"); + break; + case IT_SCHAR: + strcpy(buf, "signed char"); + break; + case IT_UCHAR: + strcpy(buf, "unsigned char"); + break; + case IT_SHORT: + strcpy(buf, "short"); + break; + case IT_USHORT: + strcpy(buf, "unsigned short"); + break; + case IT_INT: + strcpy(buf, "int"); + break; + case IT_UINT: + strcpy(buf, "unsigned int"); + break; + case IT_LONG: + strcpy(buf, "long"); + break; + case IT_ULONG: + strcpy(buf, "unsigned long"); + break; + case IT_LONGLONG: + strcpy(buf, "long long"); + break; + case IT_ULONGLONG: + strcpy(buf, "unsigned long long"); + break; + } + break; + case TYPEFLOAT: + switch (TYPE_INTEGRAL(type)->integral) { + case IT_FLOAT: + strcpy(buf, "float"); + break; + case IT_SHORTDOUBLE: + strcpy(buf, "short double"); + break; + case IT_DOUBLE: + strcpy(buf, "double"); + break; + case IT_LONGDOUBLE: + strcpy(buf, "long double"); + break; + } + break; + case TYPEENUM: + strcpy(buf, "enum "); + if (TYPE_ENUM(type)->enumname) + strcat(buf, TYPE_ENUM(type)->enumname->name); + break; + case TYPESTRUCT: + if (IS_TYPESTRUCT_VECTOR(TYPE_STRUCT(type))) { + switch (TYPE_STRUCT(type)->stype) { + case STRUCT_VECTOR_UCHAR: + strcpy(buf, "vector unsigned char "); + break; + case STRUCT_VECTOR_SCHAR: + strcpy(buf, "vector signed char "); + break; + case STRUCT_VECTOR_BCHAR: + strcpy(buf, "vector bool char "); + break; + case STRUCT_VECTOR_USHORT: + strcpy(buf, "vector unsigned short "); + break; + case STRUCT_VECTOR_SSHORT: + strcpy(buf, "vector signed short "); + break; + case STRUCT_VECTOR_BSHORT: + strcpy(buf, "vector bool short "); + break; + case STRUCT_VECTOR_UINT: + strcpy(buf, "vector unsigned long "); + break; + case STRUCT_VECTOR_SINT: + strcpy(buf, "vector signed long "); + break; + case STRUCT_VECTOR_BINT: + strcpy(buf, "vector bool long "); + break; + case STRUCT_VECTOR_FLOAT: + strcpy(buf, "vector float "); + break; + case STRUCT_VECTOR_PIXEL: + strcpy(buf, "vector pixel "); + break; + } + } else { + strcpy(buf, "struct "); + } + if (TYPE_STRUCT(type)->name) + strcat(buf, TYPE_STRUCT(type)->name->name); + break; + case TYPECLASS: + strcpy(buf, "class "); + if (TYPE_CLASS(type)->classname) + strcat(buf, TYPE_CLASS(type)->classname->name); + break; + case TYPEFUNC: + IRO_SpellType(TYPE_FUNC(type)->functype, mybuf); + strcpy(buf, "freturns("); + strcat(buf, mybuf); + strcat(buf, ")"); + break; + case TYPEBITFIELD: + IRO_SpellType(TYPE_BITFIELD(type)->bitfieldtype, mybuf); + sprintf(buf, "bitfield(%s){%d:%d}", mybuf, TYPE_BITFIELD(type)->offset, TYPE_BITFIELD(type)->bitlength); + break; + case TYPELABEL: + strcpy(buf, "label"); + break; + case TYPEPOINTER: + IRO_SpellType(TPTR_TARGET(type), mybuf); + strcpy(buf, "pointer("); + strcat(buf, mybuf); + strcat(buf, ")"); + break; + case TYPEARRAY: + IRO_SpellType(TPTR_TARGET(type), mybuf); + strcpy(buf, "array("); + strcat(buf, mybuf); + strcat(buf, ")"); + break; + case TYPEMEMBERPOINTER: + IRO_SpellType(TYPE_MEMBER_POINTER(type)->ty2, mybuf); + IRO_SpellType(TYPE_MEMBER_POINTER(type)->ty1, mybuf2); + strcpy(buf, "memberpointer("); + strcat(buf, mybuf); + strcat(buf, ","); + strcat(buf, mybuf2); + strcat(buf, ")"); + break; + } +} + diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroDump.h b/compiler_and_linker/FrontEnd/Optimizer/IroDump.h new file mode 100644 index 0000000..ad8c039 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroDump.h @@ -0,0 +1,27 @@ +#ifndef COMPILER_IRODUMP_H +#define COMPILER_IRODUMP_H + +#include "IrOptimizer.h" +#include "BitVector.h" +#include "compiler/enode.h" + +extern char *IRO_NodeName(ENodeType nodetype); +extern void IRO_InitializeNodeNamesArray(void); +extern void IRO_DumpIntTree(IROLinear *linear); +extern void IRO_DumpLinearList(IROLinear *linear); +extern void IRO_DumpBits(char *name, BitVector *bv); +extern void IRO_DumpAfterPhase(char *str, Boolean flag); +extern void IRO_LogForFunction(char *name); +extern void IRO_DumpFlowgraph(void); +extern void IRO_DumpNode(IRONode *node); +extern void IRO_DumpAssignments(void); +extern void IRO_DumpVars(void); +extern void IRO_DumpDf(void); +extern void IRO_DumpExprs(void); +extern void IRO_SetupDump(void); +extern void IRO_CleanupDump(void); +extern void IRO_Dump(char *format, ...); +extern void IRO_DumpAddr(IROAddrRecord *rec); +extern void IRO_SpellType(Type *type, char *buf); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c b/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c new file mode 100644 index 0000000..23d5d4a --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c @@ -0,0 +1,560 @@ +#include "IroEmptyLoop.h" +#include "IroDump.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroLoop.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/CInt64.h" + +// forward decls +static Boolean EmptyLoop(IRONode *fnode); +static int CanRemoveRedundantLoop(IROLoop *loop); +static int CanRemoveRedundantLoop1(IROLoop *loop); +static int RedundantLoopCheck(IROLoop *loop); +static int CheckStepOverFlow1_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2); +static int CheckStepOverFlow2_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2); + +void IRO_FindEmptyLoops(void) { + IRONode *fnode; + IRONode *pred; + UInt16 i; + UInt16 x; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + x = 0; + for (i = 0; i < fnode->numpred; i++) { + pred = IRO_NodeTable[fnode->pred[i]]; + if (Bv_IsBitSet(fnode->index, pred->dom)) { + if (!x) { + Bv_AllocVector(&InLoop, IRO_NumNodes + 1); + Bv_Clear(InLoop); + Bv_SetBit(fnode->index, InLoop); + } + x = 1; + Bv_SetBit(pred->index, InLoop); + if (pred != fnode) + AddPreds(pred); + } + } + + if (x) { + IRO_Dump("IRO_FindEmptyLoops:Found loop with header %d\n", fnode->index); + IRO_DumpBits("Loop includes: ", InLoop); + EmptyLoop(fnode); + IRO_UpdateFlagsOnInts(); + } + } + + IRO_CheckForUserBreak(); +} + +static Boolean EmptyLoop(IRONode *fnode) { + VarRecord *var; + IRONode *bestpred; + IRONode *pred; + UInt16 i; + int flag2; + IRONode *r24; + Boolean flag; + int counter; + int j; + IRONode *succ; + IRONode *bestsucc; + int counter2; + UInt32 counter3; + IROLoop *loop; + IRONode *r21; + IRONode *r20; + IROLinear *constnd; + Type *type20; + ENode *enode; + IROLinear *save; + + flag = 0; + counter = 0; + LoopNode = fnode; + FindMustReach(); + + for (var = IRO_FirstVar; var; var = var->next) + var->xA = 1; + + ComputeLoopKills(); + ComputeLoopInvariance(); + ComputeLoopInduction(); + + LoopNode = fnode; + ConditionalHeaderAtBottom = 0; + + bestpred = NULL; + flag2 = 0; + for (i = 0; i < LoopNode->numpred; i++) { + pred = IRO_NodeTable[LoopNode->pred[i]]; + if (!Bv_IsBitSet(pred->index, InLoop)) { + flag2 = 1; + if (pred->nextnode == fnode) { + CError_ASSERT(173, !bestpred || pred == bestpred); + bestpred = pred; + } + } + } + + if (!flag2) { + IRO_Dump("No predecessor outside the loop\n"); + return 0; + } + + bestsucc = NULL; + for (i = 0; i < LoopNode->numsucc; i++) { + succ = IRO_NodeTable[LoopNode->succ[i]]; + if (Bv_IsBitSet(succ->index, InLoop)) { + bestsucc = succ; + counter++; + } + } + + if (LoopNode == bestsucc && counter == 1) + flag = 1; + + if (LoopNode->last->type != IROLinearIf || LoopNode->last->type != IROLinearIfNot || flag) { + counter2 = 0; + for (j = 0; j < LoopNode->numpred; j++) { + if (Bv_IsBitSet(IRO_NodeTable[LoopNode->pred[j]]->index, InLoop)) { + r21 = IRO_NodeTable[LoopNode->pred[j]]; + counter2++; + } + } + + r24 = NULL; + counter3 = 0; + for (j = 0; j < LoopNode->numpred; j++) { + if (!Bv_IsBitSet(IRO_NodeTable[LoopNode->pred[j]]->index, InLoop)) { + r24 = IRO_NodeTable[LoopNode->pred[j]]; + counter3++; + } + } + + if (counter2 == 1 && counter3 == 1) { + if (r21->last->type == IROLinearIf) { + if ((Bv_IsBitSet(LoopNode->nextnode->index, InLoop) && !Bv_IsBitSet(r21->nextnode->index, InLoop)) || flag) { + IRO_Dump("Standard while loop layout\n"); + loop = ExtractLoopInfo(r21); + if (flag) + loop->flags |= LoopFlags_20000; + FindAssignmenttoInductionVar(loop, r24); + r20 = r24; + while (r20 && !loop->nd14 && r20->numpred == 1 && IRO_NodeTable[r20->pred[0]]->numsucc == 1) { + FindAssignmenttoInductionVar(loop, IRO_NodeTable[r20->pred[0]]); + r20 = IRO_NodeTable[r20->pred[0]]; + } + + if (CanRemoveRedundantLoop(loop)) { + IRO_Dump("EmptyLoop: # of iterations =%" PRId32 ", FinalStoreVal=%" PRId32 "\n", CInt64_GetULong(&loop->x28), CInt64_GetULong(&loop->x30)); + IRO_NopOut(r21->last->u.label.x4); + r21->last->type = IROLinearNop; + type20 = loop->induction->nd->rtype; + constnd = IRO_NewLinear(IROLinearOperand); + constnd->index = ++IRO_NumLinear; + enode = IRO_NewENode(EINTCONST); + enode->rtype = type20; + enode->data.intval = loop->x30; + constnd->u.node = enode; + constnd->rtype = type20; + + if (loop->induction->nd->type == IROLinearOp1Arg) { + save = loop->induction->nd->u.monadic; + loop->induction->nd->type = IROLinearOp2Arg; + loop->induction->nd->nodetype = EASS; + loop->induction->nd->u.diadic.left = save; + loop->induction->nd->u.diadic.right = constnd; + IRO_Paste(constnd, constnd, loop->induction->nd); + } else if (loop->induction->nd->type == IROLinearOp2Arg) { + loop->induction->nd->nodetype = EASS; + IRO_NopOut(loop->induction->nd->u.diadic.right); + loop->induction->nd->u.diadic.right = constnd; + IRO_Paste(constnd, constnd, loop->induction->nd); + } + } else if (CanRemoveRedundantLoop1(loop)) { + IRO_Dump("EmptyLoop: self recursive dowhile(--n ) loop\n"); + + r21->last->type = IROLinearNop; + type20 = loop->induction->nd->rtype; + constnd = IRO_NewLinear(IROLinearOperand); + constnd->index = ++IRO_NumLinear; + enode = IRO_NewENode(EINTCONST); + enode->rtype = type20; + enode->data.intval = cint64_zero; + constnd->u.node = enode; + constnd->rtype = type20; + + save = loop->induction->nd->u.monadic; + loop->induction->nd->type = IROLinearOp2Arg; + loop->induction->nd->nodetype = EASS; + loop->induction->nd->u.diadic.left = save; + loop->induction->nd->u.diadic.right = constnd; + IRO_Paste(constnd, constnd, loop->induction->nd); + } + } else { + IRO_Dump("NonStandard while loop layout\n"); + } + } else { + IRO_Dump("NonStandard while loop layout\n"); + } + } else { + IRO_Dump("Cannot handle Do While Loop with multiple tails\n"); + } + } + + return 0; +} + +static int CanRemoveRedundantLoop(IROLoop *loop) { + IROLinear *inner; + + if (loop->flags & LoopFlags_10000) { + IRO_Dump("CanRemoveRedundantLoop:No because detection of dowhile(n--) loop not supported\n"); + return 0; + } + + if (loop->flags & LP_LOOP_HAS_ASM) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HAS_ASM \n"); + return 0; + } + + if (loop->flags & LP_IFEXPR_NON_CANONICAL) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_IFEXPR_NON_CANONICAL \n"); + return 0; + } + + if (loop->flags & LP_LOOP_HAS_CALLS) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HAS_CALLS \n"); + return 0; + } + + if (loop->flags & LP_LOOP_HAS_CNTRLFLOW) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HAS_CNTRLFLOW \n"); + return 0; + } + + if (loop->flags & LP_INDUCTION_NOT_FOUND) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_INDUCTION_NOT_FOUND \n"); + return 0; + } + + if (loop->flags & LP_HAS_MULTIPLE_INDUCTIONS) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_HAS_MULTIPLE_INDUCTIONS \n"); + return 0; + } + + if (loop->flags & LP_LOOP_HDR_HAS_SIDEEFFECTS) { + IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HDR_HAS_SIDEEFFECTS \n"); + return 0; + } + + if (!(loop->flags & LoopFlags_200)) { + IRO_Dump("CanRemoveRedundantLoop:No because header does not follow induction update \n"); + return 0; + } + + if (!(loop->flags & LoopFlags_10000)) { + inner = loop->nd18->u.diadic.right; + if (!IRO_IsIntConstant(inner) && !(inner->flags & IROLF_LoopInvariant)) { + IRO_Dump("CanRemoveRedundantLoop:No because Loop Upper Bound is Variant in the loop\n"); + return 0; + } + + if (!loop->nd14) { + IRO_Dump("CanRemoveRedundantLoop:No because there is no initialization of loop index in PreHeader\n"); + return 0; + } + + if (!IRO_IsVariable(loop->nd14->u.diadic.left)) { + IRO_Dump("CanRemoveRedundantLoop:No because initial value of induction stored thru pointer\n"); + return 0; + } + + if (!IRO_IsUnsignedType(loop->nd14->rtype)) { + if (IRO_IsIntConstant(loop->nd14->u.diadic.right)) { + if (!CInt64_GreaterEqual(loop->nd14->u.diadic.right->u.node->data.intval, cint64_zero)) { + IRO_Dump("CanRemoveRedundantLoop:No because initial value of induction is signed but < 0\n"); + return 0; + } + } else { + IRO_Dump("CanRemoveRedundantLoop:No because initial value of induction is signed and not constant\n"); + return 0; + } + } + + if (!(loop->flags & LP_LOOP_STEP_ISPOS) && !(loop->flags & LP_LOOP_STEP_ISNEG)) { + IRO_Dump("CanRemoveRedundantLoop:No because LP_LOOP_STEP_ISPOS/LP_LOOP_STEP_ISNEG is not set\n"); + return 0; + } + + if ((loop->flags & LP_LOOP_STEP_ISPOS) && CheckStepOverFlow1_EmptyLoop(loop, &loop->x28, &loop->x30)) { + IRO_Dump("CanRemoveRedundantLoop:No because Final Value of indution will overflow\n"); + return 0; + } + + if ((loop->flags & LP_LOOP_STEP_ISNEG) && CheckStepOverFlow2_EmptyLoop(loop, &loop->x28, &loop->x30)) { + IRO_Dump("CanRemoveRedundantLoop:No because Final Value of indution will overflow\n"); + return 0; + } + } + + return RedundantLoopCheck(loop) != 0; +} + +static int CanRemoveRedundantLoop1(IROLoop *loop) { + if ((loop->flags & LoopFlags_10000) && (loop->flags & LoopFlags_20000)) { + if (loop->flags & LP_LOOP_HAS_ASM) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HAS_ASM \n"); + return 0; + } + + if (loop->flags & LP_IFEXPR_NON_CANONICAL) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_IFEXPR_NON_CANONICAL \n"); + return 0; + } + + if (loop->flags & LP_LOOP_HAS_CALLS) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HAS_CALLS \n"); + return 0; + } + + if (loop->flags & LP_LOOP_HAS_CNTRLFLOW) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HAS_CNTRLFLOW \n"); + return 0; + } + + if (loop->flags & LP_INDUCTION_NOT_FOUND) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_INDUCTION_NOT_FOUND \n"); + return 0; + } + + if (loop->flags & LP_HAS_MULTIPLE_INDUCTIONS) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_HAS_MULTIPLE_INDUCTIONS \n"); + return 0; + } + + if (loop->flags & LP_LOOP_HDR_HAS_SIDEEFFECTS) { + IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HDR_HAS_SIDEEFFECTS \n"); + return 0; + } + + if (!(loop->flags & LoopFlags_200)) { + IRO_Dump("CanRemoveRedundantLoop1:No because header does not follow induction update \n"); + return 0; + } + + if (loop->induction->nd->type == IROLinearOp1Arg && loop->induction->nd->nodetype == EPREDEC) { + if (IRO_IsUnsignedType(loop->induction->nd->rtype)) + return 1; + IRO_Dump("CanRemoveRedundantLoop1:No because induction not of the right type \n"); + return 0; + } + + IRO_Dump("CanRemoveRedundantLoop1:No because induction operator not a predec \n"); + return 0; + } else { + return 0; + } +} + +static int RedundantLoopCheck(IROLoop *loop) { + IRONode *fnode; + IROLinear *nd; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop) && fnode != loop->fnode && (nd = fnode->first)) { + while (1) { + if ((nd->index < loop->index20 || nd->index > loop->index24) && nd->type != IROLinearNop && nd->type != IROLinearLabel) { + if (IS_LINEAR_DIADIC(nd, EASS)) { + if (!(nd->flags & IROLF_Reffed)) { + if (IS_LINEAR_MONADIC(nd->u.diadic.left, EINDIRECT)) { + if (nd->u.diadic.left->rtype && CParser_IsVolatile(nd->u.diadic.left->rtype, nd->u.diadic.left->nodeflags & ENODE_FLAG_QUALS)) { + IRO_Dump(" EASS at %d fail as store to volatile memory \n", nd->index); + return 0; + } + + if ((nd->u.diadic.left->u.monadic->flags & IROLF_LoopInvariant) && (nd->u.diadic.right->flags & IROLF_LoopInvariant)) { + IRO_Dump(" EASS at %d pass\n", nd->index); + } else { + IRO_Dump(" EASS at %d fail, either LHS address or RHS is variant \n", nd->index); + return 0; + } + } else { + IRO_Dump("Found EASS nodes whose lhs root is not a EINDIRECT node\n"); + return 0; + } + } else { + IRO_Dump("Found EASS node that is referenced i.e embedded assignment\n"); + return 0; + } + } else { + if (!(nd->flags & IROLF_Reffed)) { + IRO_Dump("Found non EASS top level node in the loop\n"); + return 0; + } + } + } + + if (nd == fnode->last) + break; + nd = nd->next; + } + } + } + + return 1; +} + +static int CheckStepOverFlow1_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2) { + Boolean isUnsigned; + IROLinear *nd2; + IROLinear *nd1; + CInt64 nd2value; + CInt64 nd1value; + CInt64 addConst; + CInt64 work; + CInt64 neg1; + + nd2 = loop->nd14->u.diadic.right; + nd1 = loop->nd18->u.diadic.right; + isUnsigned = IRO_IsUnsignedType(loop->nd18->u.diadic.right->rtype); + + if (IRO_IsIntConstant(nd2) && IRO_IsIntConstant(nd1)) { + nd2value = nd2->u.node->data.intval; + nd1value = nd1->u.node->data.intval; + if (isUnsigned) { + if (CInt64_LessEqualU(nd1value, nd2value)) + return 1; + } else { + if (CInt64_LessEqual(nd1value, nd2value)) + return 1; + } + + CInt64_SetLong(&addConst, loop->induction->addConst); + CInt64_SetLong(&neg1, -1); + *val1 = CInt64_Sub(nd1value, nd2value); + *val1 = CInt64_Add(*val1, addConst); + if (IS_LINEAR_DIADIC(loop->nd18, ELESS)) + *val1 = CInt64_Add(*val1, neg1); + + CError_ASSERT(855, !CInt64_IsZero(&addConst)); + + if (isUnsigned) + *val1 = CInt64_DivU(*val1, addConst); + else + *val1 = CInt64_Div(*val1, addConst); + + if (CInt64_Equal(*val1, cint64_zero)) + return 1; + + if (isUnsigned) { + if (CInt64_LessEqualU(*val1, cint64_zero)) + CError_FATAL(877); + } else { + if (CInt64_LessEqual(*val1, cint64_zero)) + CError_FATAL(886); + } + + if (isUnsigned) { + *val2 = CInt64_MulU(*val1, addConst); + *val2 = CInt64_Add(*val2, nd2value); + } else { + *val2 = CInt64_Mul(*val1, addConst); + *val2 = CInt64_Add(*val2, nd2value); + } + } else { + return 1; + } + + CInt64_SetLong(&addConst, loop->induction->addConst); + work = CInt64_Add(nd1value, addConst); + + if (isUnsigned) { + if (CInt64_LessU(work, nd1value)) + return 1; + } else { + if (CInt64_Less(work, nd1value)) + return 1; + } + + return 0; +} + +static int CheckStepOverFlow2_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2) { + Boolean isUnsigned; + IROLinear *nd2; + IROLinear *nd1; + CInt64 nd2value; + CInt64 nd1value; + CInt64 addConst; + CInt64 work; + CInt64 neg1; + + nd1 = loop->nd14->u.diadic.right; + nd2 = loop->nd18->u.diadic.right; + isUnsigned = IRO_IsUnsignedType(loop->nd18->u.diadic.right->rtype); + + if (IRO_IsIntConstant(nd2) && IRO_IsIntConstant(nd1)) { + nd2value = nd2->u.node->data.intval; + nd1value = nd1->u.node->data.intval; + if (isUnsigned) { + if (CInt64_LessEqualU(nd1value, nd2value)) + return 1; + } else { + if (CInt64_LessEqual(nd1value, nd2value)) + return 1; + } + + CInt64_SetLong(&addConst, loop->induction->addConst); + CInt64_SetLong(&neg1, -1); + *val1 = CInt64_Sub(nd1value, nd2value); + *val1 = CInt64_Add(*val1, addConst); + if (IS_LINEAR_DIADIC(loop->nd18, EGREATER)) + *val1 = CInt64_Add(*val1, neg1); + + CError_ASSERT(995, !CInt64_IsZero(&addConst)); + + if (isUnsigned) + *val1 = CInt64_DivU(*val1, addConst); + else + *val1 = CInt64_Div(*val1, addConst); + + if (CInt64_Equal(*val1, cint64_zero)) + return 1; + + if (isUnsigned) { + if (CInt64_LessEqualU(*val1, cint64_zero)) + return 0; + } else { + if (CInt64_LessEqual(*val1, cint64_zero)) + return 0; + } + + if (isUnsigned) { + *val2 = CInt64_MulU(*val1, addConst); + *val2 = CInt64_Sub(nd1value, *val2); + } else { + *val2 = CInt64_Mul(*val1, addConst); + *val2 = CInt64_Sub(nd1value, *val2); + } + } else { + return 1; + } + + CInt64_SetLong(&addConst, loop->induction->addConst); + work = CInt64_Sub(nd2value, addConst); + + if (isUnsigned) { + if (CInt64_GreaterU(work, nd2value)) + return 1; + } else { + if (CInt64_Greater(work, nd1value)) + return 1; + } + + return 0; +} + diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.h b/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.h new file mode 100644 index 0000000..c5597e6 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.h @@ -0,0 +1,8 @@ +#ifndef COMPILER_IROEMPTYLOOP_H +#define COMPILER_IROEMPTYLOOP_H + +#include "IrOptimizer.h" + +extern void IRO_FindEmptyLoops(void); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroEval.c b/compiler_and_linker/FrontEnd/Optimizer/IroEval.c new file mode 100644 index 0000000..aba64e1 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroEval.c @@ -0,0 +1,914 @@ +#include "IroEval.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroMalloc.h" +#include "IroPointerAnalysis.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/enode.h" +#include "compiler/objects.h" +#include "compiler/types.h" + +static Boolean IsAssociativeENodeType[MAXEXPR]; + +void IRO_InitializeIsAssociativeENodeTypeArray(void) { + int i; + + for (i = 0; i < MAXEXPR; i++) + IsAssociativeENodeType[i] = 0; + + IsAssociativeENodeType[EPOSTINC] = 0; + IsAssociativeENodeType[EPOSTDEC] = 0; + IsAssociativeENodeType[EPREINC] = 0; + IsAssociativeENodeType[EPREDEC] = 0; + IsAssociativeENodeType[EINDIRECT] = 0; + IsAssociativeENodeType[EMONMIN] = 0; + IsAssociativeENodeType[EBINNOT] = 0; + IsAssociativeENodeType[ELOGNOT] = 0; + IsAssociativeENodeType[EFORCELOAD] = 0; + IsAssociativeENodeType[EMUL] = 1; + IsAssociativeENodeType[EMULV] = 1; + IsAssociativeENodeType[EDIV] = 0; + IsAssociativeENodeType[EMODULO] = 0; + IsAssociativeENodeType[EADDV] = 1; + IsAssociativeENodeType[ESUBV] = 0; + IsAssociativeENodeType[EADD] = 1; + IsAssociativeENodeType[ESUB] = 0; + IsAssociativeENodeType[ESHL] = 0; + IsAssociativeENodeType[ESHR] = 0; + IsAssociativeENodeType[ELESS] = 0; + IsAssociativeENodeType[EGREATER] = 0; + IsAssociativeENodeType[ELESSEQU] = 0; + IsAssociativeENodeType[EGREATEREQU] = 0; + IsAssociativeENodeType[EEQU] = 0; + IsAssociativeENodeType[ENOTEQU] = 0; + IsAssociativeENodeType[EAND] = 1; + IsAssociativeENodeType[EXOR] = 1; + IsAssociativeENodeType[EOR] = 1; + IsAssociativeENodeType[ELAND] = 0; + IsAssociativeENodeType[ELOR] = 0; + IsAssociativeENodeType[EASS] = 0; + IsAssociativeENodeType[EMULASS] = 0; + IsAssociativeENodeType[EDIVASS] = 0; + IsAssociativeENodeType[EMODASS] = 0; + IsAssociativeENodeType[EADDASS] = 0; + IsAssociativeENodeType[ESUBASS] = 0; + IsAssociativeENodeType[ESHLASS] = 0; + IsAssociativeENodeType[ESHRASS] = 0; + IsAssociativeENodeType[EANDASS] = 0; + IsAssociativeENodeType[EXORASS] = 0; + IsAssociativeENodeType[EORASS] = 0; + IsAssociativeENodeType[ECOMMA] = 0; + IsAssociativeENodeType[EPMODULO] = 0; + IsAssociativeENodeType[EROTL] = 0; + IsAssociativeENodeType[EROTR] = 0; + IsAssociativeENodeType[EBCLR] = 0; + IsAssociativeENodeType[EBTST] = 0; + IsAssociativeENodeType[EBSET] = 0; + IsAssociativeENodeType[ETYPCON] = 0; + IsAssociativeENodeType[EBITFIELD] = 0; + IsAssociativeENodeType[EINTCONST] = 0; + IsAssociativeENodeType[EFLOATCONST] = 0; + IsAssociativeENodeType[ESTRINGCONST] = 0; + IsAssociativeENodeType[ECOND] = 0; + IsAssociativeENodeType[EFUNCCALL] = 0; + IsAssociativeENodeType[EFUNCCALLP] = 0; + IsAssociativeENodeType[EOBJREF] = 0; + IsAssociativeENodeType[EMFPOINTER] = 0; + IsAssociativeENodeType[ENULLCHECK] = 0; + IsAssociativeENodeType[EPRECOMP] = 0; + IsAssociativeENodeType[ETEMP] = 0; + IsAssociativeENodeType[EARGOBJ] = 0; + IsAssociativeENodeType[ELOCOBJ] = 0; + IsAssociativeENodeType[ELABEL] = 0; + IsAssociativeENodeType[ESETCONST] = 0; + IsAssociativeENodeType[ENEWEXCEPTION] = 0; + IsAssociativeENodeType[ENEWEXCEPTIONARRAY] = 0; + IsAssociativeENodeType[EOBJLIST] = 0; + IsAssociativeENodeType[EMEMBER] = 0; + IsAssociativeENodeType[ETEMPLDEP] = 0; + IsAssociativeENodeType[EINSTRUCTION] = 0; + IsAssociativeENodeType[EDEFINE] = 0; + IsAssociativeENodeType[EREUSE] = 0; + IsAssociativeENodeType[EASSBLK] = 0; + IsAssociativeENodeType[EVECTOR128CONST] = 0; + IsAssociativeENodeType[ECONDASS] = 0; +} + +void IRO_TruncateValueToType(CInt64 *val, Type *type) { + if (IRO_IsUnsignedType(type)) { + switch (type->size) { + case 1: + CInt64_ConvertUInt8(val); + break; + case 2: + CInt64_ConvertUInt16(val); + break; + case 4: + CInt64_ConvertUInt32(val); + break; + } + } else { + switch (type->size) { + case 1: + CInt64_ConvertInt8(val); + break; + case 2: + CInt64_ConvertInt16(val); + break; + case 4: + CInt64_ConvertInt32(val); + break; + } + } +} + +void IRO_TruncateBitfieldValueToType(CInt64 *val, Type *type, Type *type2) { + UInt32 limit; + UInt32 i; + UInt32 j; + CInt64 work; + + work = cint64_zero; + limit = TYPE_BITFIELD(type2)->bitlength; + for (i = 0; i < limit; i++) + work = CInt64_Or(work, CInt64_Shl(cint64_one, IRO_MakeULong(i))); + *val = CInt64_And(*val, work); + + if (!IRO_IsUnsignedType(type)) { + work = cint64_zero; + for (j = 0; j <= (i - 1); j++) { + if (j == (i - 1)) + work = CInt64_Or(work, CInt64_Shl(cint64_one, IRO_MakeULong(j))); + } + if (CInt64_NotEqual(CInt64_And(work, *val), cint64_zero)) { + for (j = i - 1; j < 64; j++) + *val = CInt64_Or(*val, CInt64_Shl(cint64_one, IRO_MakeULong(j))); + } + } + + IRO_TruncateValueToType(val, type); +} + +void IRO_ConstantFolding(void) { + IROLinear *nd; + ENode *expr; + int isCompare; + int flag; + CInt64 val; + + for (nd = IRO_FirstLinear; nd; nd = nd->next) { + switch (nd->type) { + case IROLinearOp1Arg: + if (IRO_IsIntConstant(nd->u.monadic)) { + expr = NULL; + flag = 0; + val = nd->u.monadic->u.node->data.intval; + if (nd->nodetype == ETYPCON && IS_TYPE_FLOAT(nd->rtype)) { + expr = IRO_NewENode(EFLOATCONST); + if (!IRO_IsUnsignedType(nd->u.monadic->rtype)) + expr->data.floatval.value = CInt64_ConvertToLongDouble(&val); + else + expr->data.floatval.value = CInt64_ConvertUToLongDouble(&val); + expr->rtype = nd->rtype; + } else { + switch (nd->nodetype) { + case ETYPCON: + flag = 1; + break; + case ELOGNOT: + val = CInt64_Not(val); + flag = 1; + break; + case EBINNOT: + val = CInt64_Inv(val); + flag = 1; + break; + case EMONMIN: + val = CInt64_Neg(val); + flag = 1; + break; + } + + if (flag) { + IRO_TruncateValueToType(&val, nd->rtype); + expr = IRO_NewENode(EINTCONST); + expr->rtype = nd->rtype; + expr->data.intval = val; + } + } + + if (expr) { + nd->u.monadic->type = IROLinearNop; + nd->type = IROLinearOperand; + nd->u.node = expr; + } + } + break; + + case IROLinearOp2Arg: + if (IRO_IsIntConstant(nd->u.diadic.left) && !IRO_IsIntConstant(nd->u.diadic.right) && IsAssociativeENodeType[nd->nodetype]) { + IROLinear *tmp = nd->u.diadic.right; + nd->u.diadic.right = nd->u.diadic.left; + nd->u.diadic.left = tmp; + } + + if (IRO_IsIntConstant(nd->u.diadic.right) && nd->nodetype == ESUB) { + nd->nodetype = EADD; + if (IRO_IsIntConstant(nd->u.diadic.right)) { + CInt64 v; + v = CInt64_Neg(nd->u.diadic.right->u.node->data.intval); + nd->u.diadic.right->u.node->data.intval = v; + } else { + Float f; + f = CMach_CalcFloatMonadic( + nd->u.diadic.right->rtype, + '-', + nd->u.diadic.right->u.node->data.floatval); + nd->u.diadic.right->u.node->data.floatval = f; + } + } + + if ( + IRO_IsIntConstant(nd->u.diadic.right) && + IsAssociativeENodeType[nd->nodetype] && + nd->u.diadic.left->type == IROLinearOp2Arg && + nd->u.diadic.left->nodetype == nd->nodetype && + nd->u.diadic.left->rtype == nd->rtype && + IRO_IsIntConstant(nd->u.diadic.left->u.diadic.right) && + nd->u.diadic.left->u.diadic.right->rtype == nd->u.diadic.right->rtype + ) + { + IROLinear *tmp = nd->u.diadic.left; + nd->u.diadic.left = tmp->u.diadic.left; + tmp->u.diadic.left = tmp->u.diadic.right; + tmp->u.diadic.right = nd->u.diadic.right; + tmp->rtype = tmp->u.diadic.left->rtype; + nd->u.diadic.right = tmp; + nd = tmp; + } + + if (IRO_IsIntConstant(nd->u.diadic.left) && IRO_IsIntConstant(nd->u.diadic.right)) { + CInt64 val1 = nd->u.diadic.left->u.node->data.intval; + CInt64 val2 = nd->u.diadic.right->u.node->data.intval; + flag = 0; + switch (nd->nodetype) { + case EADD: + val = CInt64_Add(val1, val2); + flag = 1; + break; + case ESUB: + val = CInt64_Sub(val1, val2); + flag = 1; + break; + case EMUL: + if (IRO_IsUnsignedType(nd->rtype)) + val = CInt64_MulU(val1, val2); + else + val = CInt64_Mul(val1, val2); + flag = 1; + break; + case EDIV: + if (!CInt64_IsZero(&val2)) { + if (IRO_IsUnsignedType(nd->rtype)) + val = CInt64_DivU(val1, val2); + else + val = CInt64_Div(val1, val2); + flag = 1; + } + break; + case EMODULO: + if (!CInt64_IsZero(&val2)) { + if (IRO_IsUnsignedType(nd->rtype)) + val = CInt64_ModU(val1, val2); + else + val = CInt64_Mod(val1, val2); + flag = 1; + } + break; + case ESHL: + val = CInt64_Shl(val1, val2); + flag = 1; + break; + case ESHR: + if (IRO_IsUnsignedType(nd->rtype)) + val = CInt64_ShrU(val1, val2); + else + val = CInt64_Shr(val1, val2); + flag = 1; + break; + case EAND: + val = CInt64_And(val1, val2); + flag = 1; + break; + case EOR: + val = CInt64_Or(val1, val2); + flag = 1; + break; + case EXOR: + val = CInt64_Xor(val1, val2); + flag = 1; + break; + case ELESS: + if (IRO_IsUnsignedType(nd->u.diadic.left->rtype)) + CInt64_SetULong(&val, CInt64_LessU(val1, val2)); + else + CInt64_SetULong(&val, CInt64_Less(val1, val2)); + flag = 1; + break; + case EGREATER: + if (IRO_IsUnsignedType(nd->u.diadic.left->rtype)) + CInt64_SetULong(&val, CInt64_GreaterU(val1, val2)); + else + CInt64_SetULong(&val, CInt64_Greater(val1, val2)); + flag = 1; + break; + case ELESSEQU: + if (IRO_IsUnsignedType(nd->u.diadic.left->rtype)) + CInt64_SetULong(&val, CInt64_LessEqualU(val1, val2)); + else + CInt64_SetULong(&val, CInt64_LessEqual(val1, val2)); + flag = 1; + break; + case EGREATEREQU: + if (IRO_IsUnsignedType(nd->u.diadic.left->rtype)) + CInt64_SetULong(&val, CInt64_GreaterEqualU(val1, val2)); + else + CInt64_SetULong(&val, CInt64_GreaterEqual(val1, val2)); + flag = 1; + break; + case EEQU: + CInt64_SetULong(&val, CInt64_Equal(val1, val2)); + flag = 1; + break; + case ENOTEQU: + CInt64_SetULong(&val, CInt64_NotEqual(val1, val2)); + flag = 1; + break; + } + + if (flag) { + IRO_TruncateValueToType(&val, nd->rtype); + expr = IRO_NewENode(EINTCONST); + expr->rtype = nd->rtype; + expr->data.intval = val; + nd->u.diadic.left->type = IROLinearNop; + nd->u.diadic.right->type = IROLinearNop; + nd->type = IROLinearOperand; + nd->u.node = expr; + } + } + + if (IRO_IsFloatConstant(nd->u.diadic.left) && IRO_IsFloatConstant(nd->u.diadic.right)) { + Float fval1 = nd->u.diadic.left->u.node->data.floatval; + Float fval2 = nd->u.diadic.right->u.node->data.floatval; + Float fval; + flag = 0; + isCompare = 0; + switch (nd->nodetype) { + case EADD: + fval = CMach_CalcFloatDiadic(nd->rtype, fval1, '+', fval2); + flag = 1; + break; + case ESUB: + fval = CMach_CalcFloatDiadic(nd->rtype, fval1, '-', fval2); + flag = 1; + break; + case EMUL: + fval = CMach_CalcFloatDiadic(nd->rtype, fval1, '*', fval2); + flag = 1; + break; + case EDIV: + fval = CMach_CalcFloatDiadic(nd->rtype, fval1, '/', fval2); + flag = 1; + break; + case ELESS: + CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, '<', fval2)); + flag = 1; + isCompare = 1; + break; + case EGREATER: + CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, '>', fval2)); + flag = 1; + isCompare = 1; + break; + case ELESSEQU: + CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, TK_LESS_EQUAL, fval2)); + flag = 1; + isCompare = 1; + break; + case EGREATEREQU: + CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, TK_GREATER_EQUAL, fval2)); + flag = 1; + isCompare = 1; + break; + case EEQU: + CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, TK_LOGICAL_EQ, fval2)); + flag = 1; + isCompare = 1; + break; + case ENOTEQU: + CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, TK_LOGICAL_NE, fval2)); + flag = 1; + isCompare = 1; + break; + } + + if (flag) { + if (isCompare) { + IRO_TruncateValueToType(&val, nd->rtype); + expr = IRO_NewENode(EINTCONST); + expr->rtype = nd->rtype; + expr->data.intval = val; + nd->u.diadic.left->type = IROLinearNop; + nd->u.diadic.right->type = IROLinearNop; + nd->type = IROLinearOperand; + nd->u.node = expr; + } else { + expr = IRO_NewENode(EFLOATCONST); + expr->rtype = nd->rtype; + expr->data.floatval = fval; + nd->u.diadic.left->type = IROLinearNop; + nd->u.diadic.right->type = IROLinearNop; + nd->type = IROLinearOperand; + nd->u.node = expr; + } + } + } + + break; + } + } + + IRO_CheckForUserBreak(); +} + +Boolean IRO_EvaluateConditionals(void) { + IRONode *fnode; + IROLinear *nd; + Boolean changed = 0; + SwitchInfo *switchInfo; + SwitchCase *swcase; + char found; + CInt64 val; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + nd = fnode->last; + switch (nd->type) { + case IROLinearIf: + case IROLinearIfNot: + if (IRO_IsIntConstant(nd->u.label.x4)) { + Boolean isZero = CInt64_IsZero(&nd->u.label.x4->u.node->data.intval); + IRO_NopOut(nd->u.label.x4); + if ((isZero == 0) == (nd->type == IROLinearIf)) + nd->type = IROLinearGoto; + else + nd->type = IROLinearNop; + changed = 1; + } + break; + + case IROLinearSwitch: + if (IRO_IsIntConstant(nd->u.swtch.x4)) { + val = nd->u.swtch.x4->u.node->data.intval; + switchInfo = nd->u.swtch.info; + swcase = switchInfo->cases; + + IRO_NopOut(nd->u.swtch.x4); + nd->type = IROLinearGoto; + + found = 0; + while (swcase) { + if (CInt64_GreaterEqual(val, swcase->min) && CInt64_LessEqual(val, swcase->max)) { + found = 1; + nd->u.label.label = swcase->label; + break; + } + swcase = swcase->next; + } + + if (!found) + nd->u.label.label = switchInfo->defaultlabel; + changed = 1; + } + break; + } + } + + if (changed) { + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + } + IRO_CheckForUserBreak(); + + return changed; +} + +static int EEquConst(IROLinear *nd) { + return nd && (nd->nodetype == EEQU) && IRO_IsIntConstant(nd->u.diadic.right); +} + +static Object *VEquConst(IROLinear *nd) { + if (EEquConst(nd)) + return IRO_IsVariable(nd->u.diadic.left); + else + return NULL; +} + +static int IsConsecutive(CInt64 a, CInt64 b) { + CInt64 diff; + + if (!CInt64_Equal(a, cint64_min) && !CInt64_Equal(b, cint64_min)) { + diff = CInt64_Sub(b, a); + return CInt64_Equal(diff, cint64_one) || CInt64_Equal(diff, cint64_negone); + } + + return 0; +} + +static IROLinear *findLabel(CLabel *label) { + IROLinear *nd; + + for (nd = IRO_FirstLinear; nd; nd = nd->next) { + if (nd->type == IROLinearLabel && nd->u.label.label == label) + break; + } + + return nd; +} + +static IROLinear *leftLeaveOf(IROLinear *nd) { + switch (nd->type) { + case IROLinearOp1Arg: + return leftLeaveOf(nd->u.monadic); + case IROLinearOp2Arg: + return leftLeaveOf(nd->u.diadic.left); + case IROLinearOperand: + return nd; + default: + return NULL; + } +} + +static int checkNode(IRONode *fnode) { + IROLinear *nd; + + if (fnode->numpred <= 1) { + nd = fnode->first; + while (nd != fnode->last && (nd->type == IROLinearNop || nd->type == IROLinearLabel)) + nd = nd->next; + + if (nd == leftLeaveOf(fnode->last->u.label.x4)) + return 1; + } + + return 0; +} + +static int checkLabel(CLabel *label, IRONode *fnode) { + switch (fnode->last->type) { + case IROLinearIf: + if (label == fnode->last->u.label.label) + return 1; + break; + } + + return 0; +} + +static Object *checkExpr(Object *a, IROLinear *nd) { + Object *b = VEquConst(nd); + + if ((!a || a == b) && !IRO_HasSideEffect(nd)) + return b; + + return NULL; +} + +static int checkStruct(IRONode *fnode1, IRONode *fnode2) { + CLabel *label; + Object *var; + + if (fnode1 == fnode2) + return (int) checkExpr(NULL, fnode1->last->u.label.x4); + + label = fnode1->last->u.label.label; + var = IRO_IsVariable(fnode1->last->u.label.x4->u.monadic); + return checkNode(fnode2) && checkLabel(label, fnode2) && checkExpr(var, fnode2->last->u.label.x4); +} + +typedef struct ReduceInfo { + int x0; + int x4; + Object *x8; + IRONode *fnode; + struct ReduceInfo *next; + CInt64 val; +} ReduceInfo; + +static int MarkPattern1(ReduceInfo *info1, ReduceInfo *info2, CInt64 *val) { + ReduceInfo *scan; + + if (!info2) + return 0; + + if (info2->x0) + return MarkPattern1(info1, info2->next, val); + + for (scan = info1; scan; scan = scan->next) { + if (scan->x0 == 2) { + if (CInt64_Equal(info2->val, scan->val)) { + IRO_NopOut(scan->fnode->last); + IRO_NopOut(scan->fnode->last->u.label.x4); // right union? + scan->x0 = -1; + return MarkPattern1(info1, info2->next, val); + } + + if (IsConsecutive(info2->val, scan->val)) { + info2->x0 = 2; + if (CInt64_Greater(*val, scan->val)) + *val = scan->val; + if (CInt64_Greater(*val, info2->val)) + *val = info2->val; + MarkPattern1(scan->next, info2, val); + MarkPattern1(info1, info1->next, val); + return 1; + } + } + } + + return MarkPattern1(info1, info2->next, val); +} + +static int DoReducible1(ReduceInfo *info, CInt64 val) { + ReduceInfo *last; + ReduceInfo *scan; + IROLinear *right; + IROLinear *left; + IROLinear *typconRight; + IROLinear *typconLeft; + IROLinear *cond; + int count; + + count = 0; + for (scan = info; scan; scan = scan->next) { + if (scan->x0 == 2) { + last = scan; + count++; + } + } + + if (!count) + return 0; + + for (scan = info; scan != last; scan = scan->next) { + if (scan->x0 == 2) { + scan->x0 = -1; + IRO_NopOut(scan->fnode->last); + IRO_NopOut(scan->fnode->last->u.label.x4); + } + } + + last->x0 = -1; + + cond = last->fnode->last; + cond->u.label.x4->nodetype = ELESSEQU; + CInt64_SetULong(&cond->u.label.x4->u.diadic.right->u.node->data.intval, count - 1); + + typconLeft = IRO_NewLinear(IROLinearOp1Arg); + typconLeft->nodetype = ETYPCON; + typconLeft->rtype = IRO_UnsignedType(cond->u.label.x4->u.diadic.left->rtype); + typconLeft->index = ++IRO_NumLinear; + + typconRight = IRO_NewLinear(IROLinearOp1Arg); + *typconRight = *typconLeft; + typconRight->index = ++IRO_NumLinear; + + left = IRO_NewLinear(IROLinearOp2Arg); + left->nodetype = EADD; + left->rtype = cond->u.label.x4->u.diadic.left->rtype; + left->index = ++IRO_NumLinear; + + right = IRO_NewLinear(IROLinearOperand); + right->nodetype = EINTCONST; + right->rtype = cond->u.label.x4->u.diadic.left->rtype; + right->index = ++IRO_NumLinear; + right->u.node = IRO_NewENode(EINTCONST); + right->u.node->data.intval = CInt64_Neg(val); + right->u.node->rtype = right->rtype; + + typconLeft->next = cond->u.label.x4->u.diadic.left->next; + cond->u.label.x4->u.diadic.left->next = right; + right->next = left; + left->next = typconLeft; + + typconRight->next = cond->u.label.x4->u.diadic.right->next; + cond->u.label.x4->u.diadic.right->next = typconRight; + + typconLeft->u.monadic = left; + left->u.diadic.left = cond->u.label.x4->u.diadic.left; + left->u.diadic.right = right; + cond->u.label.x4->u.diadic.left = typconLeft; + typconRight->u.monadic = cond->u.label.x4->u.diadic.right; + cond->u.label.x4->u.diadic.right = typconRight; + + return count; +}; + +static int ReducePattern1(IRONode *startnode, IRONode *endnode) { + ReduceInfo *infos; + ReduceInfo *info; + int changed = 0; + int count; + IRONode *fnode; + int i; + int j; + CInt64 val; + + if (startnode == endnode) + return 0; + + count = 0; + for (fnode = startnode; fnode != endnode; fnode = fnode->nextnode) + count++; + + infos = oalloc(sizeof(ReduceInfo) * ++count); + + fnode = startnode; + for (i = 0; i < count; i++) { + infos[i].x0 = 0; + infos[i].x4 = 0; + infos[i].fnode = fnode; + infos[i].next = NULL; + infos[i].x8 = VEquConst(fnode->last->u.label.x4); + if (infos[i].x8) { + infos[i].val = fnode->last->u.label.x4->u.diadic.right->u.node->data.intval; + infos[i].x4 = 1; + } + fnode = fnode->nextnode; + } + + for (j = 0; j < count; j++) { + if (infos[j].x4 == 1 && infos[j].x8) { + infos[j].x4 = -1; + info = &infos[j]; + for (i = j + 1; i < count; i++) { + if (infos[j].x8 == infos[i].x8) { + info->next = &infos[i]; + info = &infos[i]; + infos[i].x4 = 0; + } + } + } + } + + for (j = 0; j < count; j++) { + if (infos[j].x4 == -1) { + for (info = &infos[j]; info; info = info->next) { + if (info->x0 == 0) { + info->x0 = 2; + val = info->val; + if (MarkPattern1(&infos[j], info->next, &val)) { + changed = 1; + DoReducible1(&infos[j], val); + } else { + info->x0 = -1; + } + } + } + } + } + + return changed; +} + +static int ReduceConsecutiveIf(IRONode *startnode, IRONode *endnode) { + IRONode *node31; + IRONode *node30; + int changed = 0; + + while (startnode != endnode) { + if (checkStruct(startnode, startnode)) + break; + startnode = startnode->nextnode; + } + + node31 = startnode; + if (startnode != endnode) { + node30 = startnode; + node31 = startnode->nextnode; + while (node31 != endnode) { + if (checkStruct(startnode, node31)) { + node30 = node31; + node31 = node31->nextnode; + } else { + node31 = node30; + break; + } + } + + if (node31 == endnode && !checkStruct(startnode, node31)) + node31 = node30; + + if (startnode != node31 && ReducePattern1(startnode, node31)) + changed = 1; + + if (node31 != endnode) + node31 = node31->nextnode; + } + + if (node31 != endnode && ReduceConsecutiveIf(node31, endnode)) + changed = 1; + + return changed; +} + +int IRO_SimplifyConditionals(void) { + IRONode *fnode; + IRONode *start; + IRONode *end; + int changed = 0; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (fnode->last->type == IROLinearIf) { + start = end = fnode; + while (fnode->nextnode && fnode->nextnode->last->type == IROLinearIf) { + end = fnode = fnode->nextnode; + } + if (start != end && ReduceConsecutiveIf(start, end)) + changed = 1; + } + } + + if (changed) { + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + } + IRO_CheckForUserBreak(); + return changed; +} + +Boolean IRO_EvaluateDefinitePointers(Object *func) { + IROLinear *nd; + Boolean result; // r29 + Boolean changed; // r28 + Boolean changed2; // r26 + IROLinear *nd2; // r25 + IROListNode *scan; // r25 + IROListNode *list; + + if (!copts.opt_pointer_analysis) + return 0; + + result = 0; + + do { + changed = 0; + + for (nd = IRO_FirstLinear; nd; nd = nd->next) { + if ( + nd->type == IROLinearOp1Arg && + nd->nodetype == EINDIRECT && + !(nd->flags & IROLF_Assigned) && + nd->pointsToFunction && + !IRO_HasSideEffect(nd) && + PointerAnalysis_IsLinearNodePointerExprDefinite(func, nd) + ) + { + list = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(func, nd, &list); + if (list) { + if (list->list.head && list->list.tail && !list->nextList) { + changed2 = IRO_LocateFather_Cut_And_Paste(nd, list->list.tail) != NULL; + if (changed2) { + IRO_PasteAfter(list->list.head, list->list.tail, nd); + for (nd2 = list->list.head; nd2 != list->list.tail->next; nd2 = nd2->next) { + if (nd2->type == IROLinearOperand && nd2->u.node->type == EOBJREF) { + if (nd2->u.node->data.objref->datatype == DDATA || nd2->u.node->data.objref->datatype == DLOCAL) + IRO_FindVar(nd2->u.node->data.objref, 1, 1); + else + nd2->u.node->data.objref->varptr = NULL; + } + } + } + changed |= changed2; + } + + while (list) { + scan = list->nextList; + IRO_free(list); + list = scan; + } + } + } + } + + result |= changed; + IRO_CheckForUserBreak(); + } while (changed); + + return result; +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroEval.h b/compiler_and_linker/FrontEnd/Optimizer/IroEval.h new file mode 100644 index 0000000..3b91f21 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroEval.h @@ -0,0 +1,14 @@ +#ifndef COMPILER_IROEVAL_H +#define COMPILER_IROEVAL_H + +#include "IrOptimizer.h" + +extern void IRO_InitializeIsAssociativeENodeTypeArray(void); +extern void IRO_TruncateValueToType(CInt64 *val, Type *type); +extern void IRO_TruncateBitfieldValueToType(CInt64 *val, Type *type, Type *type2); +extern void IRO_ConstantFolding(void); +extern Boolean IRO_EvaluateConditionals(void); +extern int IRO_SimplifyConditionals(void); +extern Boolean IRO_EvaluateDefinitePointers(Object *func); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.c b/compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.c new file mode 100644 index 0000000..c56beae --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.c @@ -0,0 +1,1531 @@ +#include "IroExprRegeneration.h" +#include "IroCSE.h" +#include "IroDump.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroSubable.h" +#include "IroTransform.h" +#include "IROUseDef.h" +#include "IroUtil.h" +#include "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); + } +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.h b/compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.h new file mode 100644 index 0000000..c74f95f --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.h @@ -0,0 +1,8 @@ +#ifndef COMPILER_IROEXPRREGENERATION_H +#define COMPILER_IROEXPRREGENERATION_H + +#include "IrOptimizer.h" + +extern void IRO_RegenerateExpressions(void); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.c b/compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.c new file mode 100644 index 0000000..2fa9875 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.c @@ -0,0 +1,439 @@ +#include "IroFlowgraph.h" +#include "IroCSE.h" +#include "IroLinearForm.h" +#include "IroPropagate.h" +#include "IROUseDef.h" +#include "IroUtil.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CompilerTools.h" +#include "compiler/Exceptions.h" +#include "compiler/InlineAsmPPC.h" + +UInt16 IRO_NumNodes; +IRONode *IRO_FirstNode; +IRONode *IRO_LastNode; +IRONode *IRO_EndNode; +IRONode **IRO_NodeTable; +BitVector *IRO_VarKills; +BitVector *IRO_Avail; +BitVector *IRO_FuncKills; +BitVector *IRO_ExprKills; + +static IRONode *StartNode(IROLinear *linear) { + IRONode *node = oalloc(sizeof(IRONode)); + + node->index = IRO_NumNodes; + node->numsucc = 0; + node->succ = NULL; + node->numpred = 0; + node->pred = NULL; + node->first = linear; + node->last = linear; + node->x16 = NULL; + node->x1A = NULL; + node->x1E = NULL; + node->x22 = NULL; + node->x26 = 0; + node->x2A = NULL; + node->dom = NULL; + node->nextnode = NULL; + node->x36 = 0; + node->x37 = 0; + node->mustreach = 0; + node->x39 = 0; + node->loopdepth = 0; + node->x3C = 0; + node->addressed = NULL; + + IRO_NumNodes++; + if (!IRO_FirstNode) + IRO_FirstNode = node; + else + IRO_LastNode->nextnode = node; + IRO_LastNode = node; + return node; +} + +static void AddSucc(IRONode *a, IRONode *b) { + a->succ[a->numsucc++] = b->index; + b->numpred++; +} + +static void AddLabelSucc(IRONode *node, CLabel *label) { + IRONode *targetnode = (IRONode *) label->stmt; + if (targetnode) { + AddSucc(node, targetnode); + targetnode->x39 = 1; + } else { + CError_FATAL(126); + } +} + +static void AddSwitchSucc(IRONode *node) { + SwitchInfo *info = node->last->u.swtch.info; + SwitchCase *curcase = info->cases; + SInt32 i = 1; + + while (curcase) { + curcase = curcase->next; + i++; + } + + node->succ = oalloc(sizeof(UInt16) * i); + for (curcase = info->cases; curcase; curcase = curcase->next) + AddLabelSucc(node, curcase->label); + AddLabelSucc(node, info->defaultlabel); +} + +static void AddPred(UInt32 a, UInt16 b) { + IRONode *node = IRO_NodeTable[a]; + node->pred[node->numpred++] = b; +} + +void IRO_ComputeSuccPred(void) { + CLabel *label; + IRONode *node; + SInt32 count; + IROLinear *linear; + ExceptionAction *action; + IAEffects effects; + UInt16 i; + + for (label = Labels; label; label = label->next) + label->stmt = NULL; + + for (node = IRO_FirstNode; node; node = node->nextnode) { + node->x39 = 0; + node->numsucc = 0; + node->numpred = 0; + node->x36 = 0; + node->x37 = 0; + if (node->first && node->first->type == IROLinearLabel) + node->first->u.label.label->stmt = (Statement *) node; + } + + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (!node->first) { + if (node->nextnode) { + node->succ = oalloc(sizeof(UInt16)); + AddSucc(node, node->nextnode); + } + } else { + linear = node->last; + next_linear: + switch (linear->type) { + case IROLinearReturn: + case IROLinearEnd: + break; + case IROLinearGoto: + node->succ = oalloc(sizeof(UInt16)); + AddLabelSucc(node, linear->u.label.label); + break; + case IROLinearIf: + case IROLinearIfNot: + node->succ = oalloc(sizeof(UInt16) * 2); + AddSucc(node, node->nextnode); + AddLabelSucc(node, linear->u.label.label); + break; + case IROLinearSwitch: + AddSwitchSucc(node); + break; + case IROLinearFunccall: + count = 1; + if (IRO_FunctionCallMightThrowException(linear)) { + for (action = linear->stmt->dobjstack; action; action = action->prev) { + if (action->type == EAT_CATCHBLOCK || action->type == EAT_SPECIFICATION) + count++; + } + } + node->succ = oalloc(sizeof(UInt16) * count); + AddSucc(node, node->nextnode); + if (IRO_FunctionCallMightThrowException(linear)) { + for (action = linear->stmt->dobjstack; action; action = action->prev) { + if (action->type == EAT_CATCHBLOCK) + AddLabelSucc(node, action->data.catch_block.catch_label); + else if (action->type == EAT_SPECIFICATION) + AddLabelSucc(node, action->data.specification.unexp_label); + } + } + break; + case IROLinearAsm: + CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects); + node->succ = oalloc(sizeof(UInt16) * (!effects.x5 + effects.numlabels)); + if (!effects.x5) + AddSucc(node, node->nextnode); + for (i = 0; i < effects.numlabels; i++) + AddLabelSucc(node, effects.labels[i]); + break; + case IROLinearOp2Arg: + if (linear->nodetype == ECOMMA) { + linear = linear->u.diadic.right; + goto next_linear; + } + default: + if (node->nextnode) { + node->succ = oalloc(sizeof(UInt16)); + AddSucc(node, node->nextnode); + } + } + } + } + + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (node->numpred) + node->pred = oalloc(sizeof(UInt16) * node->numpred); + else + node->pred = NULL; + node->numpred = 0; + } + + for (node = IRO_FirstNode; node; node = node->nextnode) { + for (i = 0; i < node->numsucc; i++) + AddPred(node->succ[i], node->index); + } + + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (node->first && node->first->type == IROLinearLabel) { + IROLinear *linear = node->first; + do { + if (linear->type == IROLinearBeginCatch || linear->type == IROLinearEndCatch || linear->type == IROLinearEndCatchDtor) { + node->x39 = 1; + break; + } + } while (linear != node->last && (linear = linear->next)); + } + } +} + +void IRO_ComputeDom(void) { + IRONode *node; + BitVector *bv; + SInt32 i; + int repeat; + + Bv_AllocVector(&IRO_FirstNode->dom, IRO_NumNodes); + Bv_SetBit(IRO_FirstNode->index, IRO_FirstNode->dom); + for (node = IRO_FirstNode->nextnode; node; node = node->nextnode) { + Bv_AllocVector(&node->dom, IRO_NumNodes); + Bv_Set(node->dom); + } + + Bv_AllocVector(&bv, IRO_NumNodes); + + do { + repeat = 0; + for (node = IRO_FirstNode->nextnode; node; node = node->nextnode) { + if (node->numpred) { + Bv_Set(bv); + for (i = 0; i < node->numpred; i++) { + Bv_And(IRO_NodeTable[node->pred[i]]->dom, bv); + } + Bv_SetBit(node->index, bv); + } else { + Bv_Clear(bv); + Bv_SetBit(node->index, bv); + } + + if (!Bv_Compare(bv, node->dom)) { + Bv_Copy(bv, node->dom); + repeat = 1; + } + } + } while (repeat); +} + +void IRO_BuildFlowgraph(IROLinear *linear) { + IROLinear *scan; + CLabel *label; + ExceptionAction *action; + IAEffects effects; + IRONode *node; + SInt32 i; + int flag; + + for (label = Labels; label; label = label->next) + label->stmt = NULL; + + scan = linear; + IRO_NumNodes = 0; + IRO_FirstNode = IRO_LastNode = IRO_EndNode = NULL; + while (scan) { + StartNode(scan); + if (scan->type == IROLinearLabel) + scan->u.label.label->stmt = (Statement *) IRO_LastNode; + + flag = 0; + while (!flag && scan->next && !(scan->next->flags & IROLF_1)) { + switch (scan->type) { + case IROLinearGoto: + case IROLinearReturn: + case IROLinearEntry: + case IROLinearExit: + case IROLinearEnd: + flag = 1; + break; + case IROLinearIf: + case IROLinearIfNot: + case IROLinearSwitch: + flag = 1; + skip: + if (scan->next->type == IROLinearLabel) { + IROLinear *nw = IRO_NewLinear(IROLinearNop); + nw->index = ++IRO_NumLinear; + nw->next = scan->next; + scan->next = nw; + } + break; + case IROLinearFunccall: + if (IRO_FunctionCallMightThrowException(scan)) { + for (action = scan->stmt->dobjstack; action; action = action->prev) { + if (action->type == EAT_CATCHBLOCK || action->type == EAT_SPECIFICATION) { + flag = 1; + goto skip; + } + } + } + break; + case IROLinearAsm: + CodeGen_GetAsmEffects(scan->u.asm_stmt, &effects); + if (effects.numlabels) + flag = 1; + break; + } + if (!flag) + scan = scan->next; + } + + if (scan->type == IROLinearEnd) + IRO_EndNode = IRO_LastNode; + IRO_LastNode->last = scan; + scan = scan->next; + } + + IRO_NodeTable = oalloc(IRO_NumNodes * sizeof(IRONode *)); + memset(IRO_NodeTable, 0, IRO_NumNodes * sizeof(IRONode *)); + for (node = IRO_FirstNode, i = 0; node; node = node->nextnode) + IRO_NodeTable[i++] = node; + + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + IRO_CheckForUserBreak(); +} + +IRONode *IRO_NewFlowGraphNode(void) { + IRONode *node = oalloc(sizeof(IRONode)); + memset(node, 0, sizeof(IRONode)); + node->index = IRO_NumNodes; + IRO_NumNodes++; + node->nextnode = NULL; + return node; +} + +IRONode *IRO_MergeFlowGraphNodes(IRONode *a, IRONode *b) { + IRONode *succ; + Boolean found; + UInt32 i; + UInt32 j; + UInt32 k; + + if (a->nextnode == b && a->last && b->first && a->last->next == b->first) { + if (b->first->type == IROLinearLabel) + IRO_NopOut(b->first); + + a->nextnode = b->nextnode; + a->last = b->last; + + for (i = 0; i < a->numsucc; i++) { + if (b->index == a->succ[i]) { + for (j = i; j < a->numsucc; j++) { + if ((j + 1) < a->numsucc) + a->succ[j] = a->succ[j + 1]; + else + a->succ[j] = 0; + } + a->numsucc--; + break; + } + } + + for (i = 0; i < b->numsucc; i++) { + succ = IRO_NodeTable[b->succ[i]]; + for (j = 0; j < a->numsucc; j++) { + if (b->succ[i] == a->succ[j]) + break; + } + + if (j == a->numsucc) { + AddSucc(a, IRO_NodeTable[b->succ[i]]); + succ->numpred--; + } + + found = 0; + for (j = 0; j < succ->numpred; j++) { + if (a->index == succ->pred[j]) { + found = 1; + break; + } + } + + for (j = 0; j < succ->numpred; j++) { + if (b->index == succ->pred[j]) { + if (!found) { + succ->pred[j] = a->index; + } else { + for (k = j; k < succ->numpred; k++) { + if ((k + 1) < succ->numpred) + succ->pred[k] = succ->pred[k + 1]; + else + succ->pred[k] = 0; + } + succ->numpred--; + } + break; + } + } + } + + b->numsucc = b->numpred = 0; + b->first = b->last = NULL; + b->nextnode = NULL; + b->x36 = 0; + b->x37 = 0; + b->mustreach = 0; + b->x39 = 0; + b->loopdepth = 0; + + if (IRO_LastNode == b) + IRO_LastNode = a; + + if (IRO_FirstExpr && IRO_LastExpr) { + IROExpr *expr; + for (expr = IRO_FirstExpr; expr && expr != IRO_LastExpr->next; expr = expr->next) { + if (expr->node == b) + expr->node = a; + } + } + + if (IRO_FirstAssign && IRO_LastAssign) { + IROAssign *assign; + for (assign = IRO_FirstAssign; assign && assign != IRO_LastAssign->next; assign = assign->next) { + if (assign->node == b) + assign->node = a; + } + } + + if (IRO_FirstVarUse && IRO_LastVarUse) { + IROUse *use; + for (use = IRO_FirstVarUse; use && use != IRO_LastVarUse->globalnext; use = use->globalnext) { + if (use->node == b) + use->node = a; + } + } + + IRO_NodeTable[b->index] = NULL; + return a; + } + + return NULL; +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.h b/compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.h new file mode 100644 index 0000000..13ddce9 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.h @@ -0,0 +1,97 @@ +#ifndef COMPILER_IROFLOWGRAPH_H +#define COMPILER_IROFLOWGRAPH_H + +#include "IrOptimizer.h" +#include "BitVector.h" +#include "compiler/CError.h" +#include "compiler/CompilerTools.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif + +struct IRONode { + UInt16 index; + UInt16 numsucc; + UInt16 *succ; + UInt16 numpred; + UInt16 *pred; + IROLinear *first; + IROLinear *last; + BitVector *x16; // In + BitVector *x1A; // Out + BitVector *x1E; // Gen + BitVector *x22; // Kill + UInt32 x26; + BitVector *x2A; // AA + BitVector *dom; + IRONode *nextnode; + Boolean x36; + Boolean x37; + Boolean mustreach; + Boolean x39; + UInt16 loopdepth; + Boolean x3C; + struct ObjectSet *addressed; + Boolean mustreach1; +}; + +typedef struct IRONodes { + UInt16 *indices; + UInt16 num; + UInt16 base; +} IRONodes; + +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +extern UInt16 IRO_NumNodes; +extern IRONode *IRO_FirstNode; +extern IRONode *IRO_LastNode; +extern IRONode *IRO_EndNode; +extern IRONode **IRO_NodeTable; +extern BitVector *IRO_VarKills; +extern BitVector *IRO_Avail; +extern BitVector *IRO_FuncKills; +extern BitVector *IRO_ExprKills; + +extern void IRO_ComputeSuccPred(void); +extern void IRO_ComputeDom(void); +extern void IRO_BuildFlowgraph(IROLinear *linear); +extern IRONode *IRO_NewFlowGraphNode(void); +extern IRONode *IRO_MergeFlowGraphNodes(IRONode *a, IRONode *b); + +CW_INLINE void IROFlowgraph_sub_4C2140(IRONodes *nodes) { + nodes->indices = oalloc(sizeof(UInt16) * IRO_NumNodes); + nodes->num = 0; + nodes->base = 0; +} + +CW_INLINE void IROFlowgraph_sub_4C20E0(IRONodes *nodes) { +} + +CW_INLINE UInt16 IROFlowgraph_sub_4C2040(IRONodes *nodes) { + return nodes->num; +} + +CW_INLINE UInt16 IROFlowgraph_sub_4C2100(IRONodes *nodes) { + UInt16 result = -1; + if (nodes->num) { + result = nodes->indices[nodes->base]; + nodes->base = (nodes->base + 1) % IRO_NumNodes; + nodes->num--; + } + return result; +} + +CW_INLINE void IROFlowgraph_sub_4C3880(IRONodes *nodes, UInt16 index) { + if (nodes->num < IRO_NumNodes) { + nodes->indices[(nodes->base + nodes->num) % IRO_NumNodes] = index; + nodes->num++; + } else { + CError_FATAL(93); + } +} + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroJump.c b/compiler_and_linker/FrontEnd/Optimizer/IroJump.c new file mode 100644 index 0000000..9af248e --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroJump.c @@ -0,0 +1,267 @@ +#include "IroJump.h" +#include "IroDump.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroUtil.h" +#include "compiler/CFunc.h" +#include "compiler/Exceptions.h" + +static Boolean CheckChain(CLabel **labelptr) { + IRONode *node; + + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (node->first && node->first->type == IROLinearLabel && node->first->u.label.label == *labelptr) { + IROLinear *linear; + CLabel *lab; + for (linear = node->first->next, lab = NULL; linear && (linear->type == IROLinearLabel || linear->type == IROLinearNop); linear = linear->next) { + if (linear->type == IROLinearLabel) + lab = linear->u.label.label; + } + + if (linear->type == IROLinearGoto && *labelptr != linear->u.label.label) { + *labelptr = linear->u.label.label; + IRO_Dump("Chaining goto at %d\n", linear->index); + return 1; + } + + if (lab && *labelptr != lab) + *labelptr = lab; + return 0; + } + } + + return 0; +} + +Boolean IRO_DoJumpChaining(void) { + IRONode *node; + IROLinear *linear; + Boolean flag; + SwitchInfo *info; + SwitchCase *curcase; + Boolean result; + + result = 0; + do { + flag = 0; + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (node->first) { + linear = node->last; + switch (linear->type) { + case IROLinearGoto: + if (CheckChain(&linear->u.label.label)) + flag = 1; + break; + case IROLinearIf: + case IROLinearIfNot: + if (CheckChain(&linear->u.label.label)) + flag = 1; + break; + case IROLinearSwitch: + info = linear->u.swtch.info; + for (curcase = info->cases; curcase; curcase = curcase->next) { + if (CheckChain(&curcase->label)) + flag = 1; + } + if (CheckChain(&info->defaultlabel)) + flag = 1; + break; + } + } + } + result |= flag; + IRO_CheckForUserBreak(); + } while (flag); + + return result; +} + +void IRO_MakeReachable(IRONode *node) { + UInt16 i; + Boolean flag; + + node->x36 = 1; + do { + flag = 0; + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (node->x36 && !node->x37) { + for (i = 0; i < node->numsucc; i++) { + if (!IRO_NodeTable[node->succ[i]]->x36) { + flag = 1; + IRO_NodeTable[node->succ[i]]->x36 = 1; + } + } + node->x37 = 1; + } + } + } while (flag); +} + +Boolean IRO_RemoveUnreachable(void) { + IRONode *node2; + IRONode *node1; + IROLinear *scan; + IROLinear *linear; + Boolean result; + ExceptionAction **actptr; + ExceptionAction *act; + + result = 0; + IRO_ComputeSuccPred(); + IRO_MakeReachable(IRO_FirstNode); + node1 = IRO_FirstNode; + for (node2 = IRO_FirstNode->nextnode; node2; node2 = node2->nextnode) { + if (node2->first && !node2->x36) { + IRO_Dump("Removing unreachable code at: %d\n", node2->index); + node1->nextnode = node2->nextnode; + node1->last->next = node2->last->next; + result = 1; + for (linear = node2->first; linear && linear->type == IROLinearLabel && linear != node2->last->next; linear = linear->next) { + for (scan = IRO_FirstLinear; scan; scan = scan->next) { + if (scan->stmt) + scan->stmt->marked = 0; + } + + for (scan = IRO_FirstLinear; scan; scan = scan->next) { + if (scan->stmt && !scan->stmt->marked) { + scan->stmt->marked = 1; + for (actptr = &scan->stmt->dobjstack; (act = *actptr); actptr = &act->prev) { + if ( + (act->type == EAT_CATCHBLOCK && act->data.catch_block.catch_label == linear->u.label.label) || + (act->type == EAT_SPECIFICATION && act->data.specification.unexp_label == linear->u.label.label)) { + *actptr = act->prev; + } + } + } + } + } + if (node2 == IRO_LastNode) + IRO_LastNode = node1; + } else { + node1 = node2; + } + } + + if (result) { + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + } + + IRO_CheckForUserBreak(); + return result; +} + +Boolean IRO_RemoveRedundantJumps(void) { + IRONode *node; + IROLinear *linear; + IROLinear *scan; + IROLinear *scan2; + SwitchInfo *info; + SwitchCase *curcase; + Boolean result; + + result = 0; + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (node->first) { + linear = node->last; + switch (linear->type) { + case IROLinearGoto: + scan = linear->next; + while (scan && ((scan->type == IROLinearNop) || (scan->type == IROLinearLabel && scan->u.label.label != linear->u.label.label))) + scan = scan->next; + while (1) { + if (!scan) break; + if (scan->type != IROLinearLabel) break; + if (scan->u.label.label == linear->u.label.label) { + IRO_Dump("Removing goto next at %d\n", linear->index); + linear->type = IROLinearNop; + result = 1; + break; + } + scan = scan->next; + } + break; + + case IROLinearIf: + case IROLinearIfNot: + scan = linear->next; + while (scan && scan->type == IROLinearNop) + scan = scan->next; + if (scan && scan->type == IROLinearGoto) { + scan2 = scan->next; + while (scan2 && ((scan2->type == IROLinearNop) || (scan2->type == IROLinearLabel && scan2->u.label.label != linear->u.label.label))) + scan2 = scan2->next; + + if (scan2 && scan2->type == IROLinearLabel && scan2->u.label.label == linear->u.label.label) { + if (linear->type == IROLinearIf) + linear->type = IROLinearIfNot; + else + linear->type = IROLinearIf; + + linear->u.label.label = scan->u.label.label; + scan->type = IROLinearNop; + IRO_Dump("Removing branch around goto at %d\n", linear->index); + result = 1; + } + } + + scan2 = linear->next; + while (scan2 && ((scan2->type == IROLinearNop) || (scan2->type == IROLinearLabel && scan2->u.label.label != linear->u.label.label))) + scan2 = scan2->next; + while (1) { + if (!scan2) break; + if (scan2->type != IROLinearLabel) break; + if (scan2->u.label.label == linear->u.label.label) { + IRO_Dump("Removing If/IfNot_Goto next at %d\n", linear->index); + linear->type = IROLinearNop; + IRO_CheckSideEffect(linear->u.label.x4); + result = 1; + break; + } + scan2 = scan2->next; + } + break; + + case IROLinearSwitch: + info = linear->u.swtch.info; + curcase = info->cases; + while (curcase && curcase->label == info->defaultlabel) + curcase = curcase->next; + if (!curcase) { + IRO_Dump("Removing Switch next at %d\n", linear->index); + IRO_CheckSideEffect(linear->u.swtch.x4); + linear->type = IROLinearGoto; + linear->u.label.label = info->defaultlabel; + result = 1; + } + break; + } + } + } + + if (result) { + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + } + + IRO_CheckForUserBreak(); + return result; +} + +Boolean IRO_RemoveLabels(void) { + Boolean result; + IRONode *node; + + result = 0; + IRO_ComputeSuccPred(); + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (node->first && node->first->type == IROLinearLabel && !node->x39) { + node->first->type = IROLinearNop; + node->first->flags &= ~IROLF_1; + result = 1; + } + } + + IRO_CheckForUserBreak(); + return result; +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroJump.h b/compiler_and_linker/FrontEnd/Optimizer/IroJump.h new file mode 100644 index 0000000..62b7be6 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroJump.h @@ -0,0 +1,12 @@ +#ifndef COMPILER_IROJUMP_H +#define COMPILER_IROJUMP_H + +#include "IrOptimizer.h" + +extern Boolean IRO_DoJumpChaining(void); +extern void IRO_MakeReachable(IRONode *node); +extern Boolean IRO_RemoveUnreachable(void); +extern Boolean IRO_RemoveRedundantJumps(void); +extern Boolean IRO_RemoveLabels(void); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.c b/compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.c new file mode 100644 index 0000000..8c5b0d8 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.c @@ -0,0 +1,1797 @@ +#include "IroLinearForm.h" +#include "IroDump.h" +#include "IroFlowgraph.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInt64.h" +#include "compiler/CParser.h" +#include "compiler/CompilerTools.h" +#include "compiler/InlineAsm.h" +#include "compiler/InlineAsmPPC.h" +#include "compiler/types.h" + +typedef struct NullCheckListNode { + SInt32 precompid; + Object *tempobj; + struct NullCheckListNode *next; +} NullCheckListNode; + +IROLinear *IRO_FirstLinear; +IROLinear *IRO_LastLinear; +UInt32 IRO_NumLinear; +Statement *CurStat; +static NullCheckListNode *NullCheckList; +static Statement *CurrStmt; +static Statement *PrevStmt; + +static void LinkLinear(IROLinear *linear) { + linear->index = IRO_NumLinear++; + if (IRO_FirstLinear) + IRO_LastLinear->next = linear; + else + IRO_FirstLinear = linear; + IRO_LastLinear = linear; +} + +IROLinear *IRO_NewLinear(IROLinearType type) { + IROLinear *linear = oalloc(sizeof(IROLinear)); + memset(linear, 0, sizeof(IROLinear)); + linear->stmt = CurStat; + linear->nodetype = EPOSTINC; + linear->next = NULL; + linear->type = type; + linear->rtype = NULL; + linear->flags = 0; + linear->nodeflags = 0; + linear->expr = NULL; + linear->x16 = 0; + return linear; +} + +static void MarkAssigned(IROLinear *linear, Boolean flag) { + IROLinear *inner; + IROAddrRecord *rec; + + if (IS_LINEAR_MONADIC(linear, EINDIRECT) && IS_LINEAR_MONADIC(linear->u.monadic, EBITFIELD)) { + linear->flags |= IROLF_Assigned; + inner = linear->u.monadic->u.monadic; + if (inner->type == IROLinearOperand) { + inner->flags |= IROLF_Assigned; + if (flag) { + linear->flags |= IROLF_Used; + inner->flags |= IROLF_Used; + } + } + + if (IS_LINEAR_DIADIC(inner, EADD)) { + if (IS_LINEAR_ENODE(inner->u.diadic.left, EOBJREF)) { + if (IS_LINEAR_ENODE(inner->u.diadic.right, EINTCONST)) + inner->u.diadic.left->flags |= IROLF_Assigned; + if (flag) { + linear->flags |= IROLF_Used; + inner->u.diadic.left->flags |= IROLF_Used; + } + } + + rec = IRO_InitAddrRecordPointer(inner); + IRO_DecomposeAddressExpression(inner, rec); + if (rec->numObjRefs == 1 && IS_LINEAR_ENODE(inner->u.diadic.left, EOBJREF)) { + ((IROLinear *) rec->objRefs->element)->flags |= IROLF_Assigned; + if (flag) { + linear->flags |= IROLF_Used; + ((IROLinear *) rec->objRefs->element)->flags |= IROLF_Used; + } + } + } + } + + if (IS_LINEAR_MONADIC(linear, EINDIRECT)) { + linear->flags |= IROLF_Assigned; + if (linear->u.monadic->type == IROLinearOperand) { + linear->u.monadic->flags |= IROLF_Assigned; + if (flag) { + linear->flags |= IROLF_Used; + linear->u.monadic->flags |= IROLF_Used; + } + } + } + + if (IS_LINEAR_MONADIC(linear, EINDIRECT)) { + linear->flags |= IROLF_Assigned; + inner = linear->u.monadic; + + if (IS_LINEAR_DIADIC(inner, EADD)) { + if (IS_LINEAR_ENODE(inner->u.diadic.left, EOBJREF)) { + if (IS_LINEAR_ENODE(inner->u.diadic.right, EINTCONST)) + inner->u.diadic.left->flags |= IROLF_Assigned; + if (flag) { + linear->flags |= IROLF_Used; + inner->u.diadic.left->flags |= IROLF_Used; + } + } + + rec = IRO_InitAddrRecordPointer(inner); + IRO_DecomposeAddressExpression(inner, rec); + if (rec->numObjRefs == 1 && IS_LINEAR_ENODE(inner->u.diadic.left, EOBJREF)) { + ((IROLinear *) rec->objRefs->element)->flags |= IROLF_Assigned; + if (flag) { + linear->flags |= IROLF_Used; + ((IROLinear *) rec->objRefs->element)->flags |= IROLF_Used; + } + } + } + } +} + +static void MarkSubscript(IROLinear *linear) { + linear->flags |= IROLF_Subs; + if (IS_LINEAR_DIADIC(linear, EADD)) { + if (IRO_IsAddressMultiply(linear->u.diadic.left) || IS_LINEAR_MONADIC(linear->u.diadic.left, EINDIRECT)) + linear->u.diadic.left->flags |= IROLF_Subs; + if (IRO_IsAddressMultiply(linear->u.diadic.right) || IS_LINEAR_MONADIC(linear->u.diadic.right, EINDIRECT)) + linear->u.diadic.right->flags |= IROLF_Subs; + + if (IS_LINEAR_DIADIC(linear->u.diadic.left, EADD)) + MarkSubscript(linear->u.diadic.left); + if (IS_LINEAR_DIADIC(linear->u.diadic.right, EADD)) + MarkSubscript(linear->u.diadic.right); + } +} + +static void MarkArgs(IROLinear *linear) { + int i; + linear->flags |= IROLF_4000; + + switch (linear->type) { + case IROLinearEnd: + break; + case IROLinearOp1Arg: + case IROLinearBeginCatch: + case IROLinearEndCatch: + case IROLinearEndCatchDtor: + MarkArgs(linear->u.monadic); + break; + case IROLinearOp2Arg: + MarkArgs(linear->u.diadic.left); + MarkArgs(linear->u.diadic.right); + break; + case IROLinearIf: + case IROLinearIfNot: + MarkArgs(linear->u.label.x4); + break; + case IROLinearReturn: + if (linear->u.monadic) + MarkArgs(linear->u.monadic); + break; + case IROLinearSwitch: + MarkArgs(linear->u.swtch.x4); + break; + case IROLinearOp3Arg: + MarkArgs(linear->u.args3.a); + MarkArgs(linear->u.args3.b); + MarkArgs(linear->u.args3.c); + break; + case IROLinearFunccall: + MarkArgs(linear->u.funccall.linear8); + for (i = 0; i < linear->u.funccall.argCount; i++) + MarkArgs(linear->u.funccall.args[i]); + break; + } +} + +// assumed name, position +CW_INLINE void MarkSubExpr(IROLinear *linear) { + int i; + + switch (linear->type) { + case IROLinearNop: + case IROLinearOperand: + case IROLinearGoto: + case IROLinearLabel: + case IROLinearEntry: + case IROLinearExit: + case IROLinearAsm: + case IROLinearEnd: + break; + case IROLinearOp1Arg: + case IROLinearBeginCatch: + case IROLinearEndCatch: + case IROLinearEndCatchDtor: + linear->u.monadic->flags |= IROLF_Reffed; + break; + case IROLinearOp2Arg: + linear->u.diadic.left->flags |= IROLF_Reffed; + linear->u.diadic.right->flags |= IROLF_Reffed; + break; + case IROLinearIf: + case IROLinearIfNot: + linear->u.label.x4->flags |= IROLF_Reffed; + break; + case IROLinearReturn: + if (linear->u.monadic) + linear->u.monadic->flags |= IROLF_Reffed; + break; + case IROLinearSwitch: + linear->u.swtch.x4->flags |= IROLF_Reffed; + break; + case IROLinearOp3Arg: + linear->u.args3.a->flags |= IROLF_Reffed; + linear->u.args3.b->flags |= IROLF_Reffed; + linear->u.args3.c->flags |= IROLF_Reffed; + break; + case IROLinearFunccall: + linear->u.funccall.linear8->flags |= IROLF_Reffed; + for (i = 0; i < linear->u.funccall.argCount; i++) + linear->u.funccall.args[i]->flags |= IROLF_Reffed; + break; + default: + CError_FATAL(368); + } +} + +static void MarkSubs1(IROLinear *linear) { + IROAddrRecord *rec; + + if (IS_LINEAR_MONADIC(linear, EBITFIELD)) { + linear = linear->u.monadic; + if (IS_LINEAR_ENODE(linear, EOBJREF)) + linear->flags |= IROLF_Ind; + } + + if (IS_LINEAR_DIADIC(linear, EADD)) { + if (IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF) && IS_LINEAR_ENODE(linear->u.diadic.right, EINTCONST)) + linear->u.diadic.left->flags |= IROLF_Ind; + + rec = IRO_InitAddrRecordPointer(linear); + IRO_DecomposeAddressExpression(linear, rec); + if (rec->numObjRefs == 1 && IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF)) + ((IROLinear *) rec->objRefs->element)->flags |= IROLF_Ind; + } +} + +static void MakeLeftChildAsAssignment(ENode *enode) { + Statement *stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + stmt->expr = enode->data.diadic.left; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void AssignCommaRToTemp(ENode *enode, Boolean flag) { + Statement *stmt; + + if (!IS_TYPE_VOID(enode->rtype) && !flag) { + Object *obj = create_temp_object(enode->rtype); + ENode *indnode = IRO_NewENode(EINDIRECT); + indnode->data.monadic = create_objectrefnode(obj); + + if (!IS_TYPE_VOID(enode->rtype)) + indnode->rtype = enode->rtype; + else + CError_FATAL(548); + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + stmt->expr = IRO_NewENode(EASS); + stmt->expr->data.diadic.left = indnode; + stmt->expr->data.diadic.right = enode->data.diadic.right; + stmt->expr->rtype = enode->rtype; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; + + enode->type = EINDIRECT; + enode->data.monadic = create_objectrefnode(obj); + CError_ASSERT(580, !IS_TYPE_VOID(enode->rtype)); + } else { + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + stmt->expr = enode->data.diadic.right; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; + + enode->type = EINTCONST; + enode->data.intval = cint64_zero; + } +} + +static void AssignDangerousArgumentToTemp(ENode *enode) { + Statement *stmt; + Object *obj; + ENode *indnode; + ENode *rightnode; + + obj = create_temp_object(enode->rtype); + indnode = IRO_NewENode(EINDIRECT); + indnode->data.monadic = create_objectrefnode(obj); + + if (!IS_TYPE_VOID(enode->rtype)) + indnode->rtype = enode->rtype; + else + CError_FATAL(627); + + rightnode = IRO_NewENode(enode->type); + memcpy(rightnode, enode, sizeof(ENode)); + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + stmt->expr = IRO_NewENode(EASS); + stmt->expr->data.diadic.left = indnode; + stmt->expr->data.diadic.right = rightnode; + stmt->expr->rtype = enode->rtype; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; + + enode->type = EINDIRECT; + enode->data.monadic = create_objectrefnode(obj); +} + +static void CreateTempAssignmentToZero(ENode *enode, Object **objptr) { + Statement *stmt; + ENode *indnode; + ENode *rightnode; + + *objptr = create_temp_object(enode->rtype); + indnode = IRO_NewENode(EINDIRECT); + indnode->data.monadic = create_objectrefnode(*objptr); + if (!IS_TYPE_VOID(enode->rtype)) + indnode->rtype = enode->rtype; + else + CError_FATAL(678); + + rightnode = IRO_NewENode(EINTCONST); + rightnode->data.intval = cint64_zero; + rightnode->rtype = enode->rtype; + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + stmt->expr = IRO_NewENode(EASS); + stmt->expr->data.diadic.left = indnode; + stmt->expr->data.diadic.right = rightnode; + stmt->expr->rtype = enode->rtype; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void CreateTempAssignmentToOne(ENode *enode, Object **objptr) { + Statement *stmt; + ENode *indnode; + ENode *rightnode; + + *objptr = create_temp_object(enode->rtype); + indnode = IRO_NewENode(EINDIRECT); + indnode->data.monadic = create_objectrefnode(*objptr); + if (!IS_TYPE_VOID(enode->rtype)) + indnode->rtype = enode->rtype; + else + CError_FATAL(720); + + rightnode = IRO_NewENode(EINTCONST); + rightnode->data.intval = cint64_one; + rightnode->rtype = enode->rtype; + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + stmt->expr = IRO_NewENode(EASS); + stmt->expr->data.diadic.left = indnode; + stmt->expr->data.diadic.right = rightnode; + stmt->expr->rtype = enode->rtype; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void GenerateCondExpression(ENode *enode, CLabel **label) { + Statement *stmt; + + *label = IRO_NewLabel(); + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_IFNGOTO; + stmt->expr = enode->data.cond.cond; + stmt->label = *label; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void GenerateGoToStmt(ENode *enode, CLabel **label) { + Statement *stmt; + + *label = IRO_NewLabel(); + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_GOTO; + stmt->label = *label; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void PutTempOnNullCheckList(ENode *expr, Object *obj) { + NullCheckListNode *n = lalloc(sizeof(NullCheckListNode)); + n->precompid = expr->data.nullcheck.precompid; + n->tempobj = obj; + n->next = NULL; + if (NullCheckList) { + n->next = NullCheckList; + NullCheckList = n; + } else { + NullCheckList = n; + } +} + +static Object *GetTempFromtheList(ENode *expr) { + NullCheckListNode *n; + + for (n = NullCheckList; n; n = n->next) { + if (n->precompid == expr->data.precompid) + break; + } + + CError_ASSERT(839, n); + return n->tempobj; +} + +static void GenerateNullcheckExprTempAssignment(ENode *enode, Object **objptr) { + Statement *stmt; + ENode *indnode; + + if (!IS_TYPE_VOID(enode->rtype)) + *objptr = create_temp_object(enode->rtype); + else + *objptr = create_temp_object(enode->data.nullcheck.nullcheckexpr->rtype); + + PutTempOnNullCheckList(enode, *objptr); + + indnode = IRO_NewENode(EINDIRECT); + indnode->data.monadic = create_objectrefnode(*objptr); + if (!IS_TYPE_VOID(enode->rtype)) + indnode->rtype = enode->rtype; + else + indnode->rtype = enode->data.nullcheck.nullcheckexpr->rtype; + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + stmt->expr = IRO_NewENode(EASS); + stmt->expr->data.diadic.left = indnode; + stmt->expr->data.diadic.right = enode->data.nullcheck.nullcheckexpr; + if (!IS_TYPE_VOID(enode->rtype)) + stmt->expr->rtype = enode->rtype; + else + stmt->expr->rtype = enode->data.nullcheck.nullcheckexpr->rtype; + + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void GenerateExpr1TempAssignment(ENode *enode, Object **objptr) { + Statement *stmt; + ENode *indnode; + + if (!IS_TYPE_VOID(enode->rtype)) { + *objptr = create_temp_object(enode->rtype); + indnode = IRO_NewENode(EINDIRECT); + indnode->data.monadic = create_objectrefnode(*objptr); + indnode->rtype = enode->rtype; + CError_ASSERT(905, !IS_TYPE_VOID(enode->rtype)); + } + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + if (!IS_TYPE_VOID(enode->rtype)) { + stmt->expr = IRO_NewENode(EASS); + stmt->expr->data.diadic.left = indnode; + stmt->expr->data.diadic.right = enode->data.cond.expr1; + stmt->expr->rtype = enode->rtype; + } else { + stmt->expr = enode->data.cond.expr1; + } + + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void GenerateExpr2TempAssignment(ENode *enode, Object **objptr) { + Statement *stmt; + ENode *indnode; + + if (!IS_TYPE_VOID(enode->rtype)) { + indnode = IRO_NewENode(EINDIRECT); + indnode->data.monadic = create_objectrefnode(*objptr); + indnode->rtype = enode->rtype; + CError_ASSERT(953, !IS_TYPE_VOID(enode->rtype)); + } + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + if (!IS_TYPE_VOID(enode->rtype)) { + stmt->expr = IRO_NewENode(EASS); + stmt->expr->data.diadic.left = indnode; + stmt->expr->data.diadic.right = enode->data.cond.expr2; + stmt->expr->rtype = enode->rtype; + } else { + stmt->expr = enode->data.cond.expr2; + } + + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void GenerateForceLoadTempAssignment(ENode *enode, Object **objptr) { + Statement *stmt; + ENode *indnode; + + if (!IS_TYPE_VOID(enode->rtype)) { + *objptr = create_temp_object(enode->rtype); + indnode = IRO_NewENode(EINDIRECT); + indnode->data.monadic = create_objectrefnode(*objptr); + indnode->rtype = enode->rtype; + CError_ASSERT(1003, !IS_TYPE_VOID(enode->rtype)); + } + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + if (!IS_TYPE_VOID(enode->rtype)) { + stmt->expr = IRO_NewENode(EASS); + stmt->expr->data.diadic.left = indnode; + stmt->expr->data.diadic.right = enode->data.monadic; + stmt->expr->rtype = enode->rtype; + } else { + stmt->expr = enode->data.monadic; + } + + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void GenerateLabel(CLabel **labelptr) { + Statement *stmt; + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_LABEL; + stmt->label = *labelptr; + stmt->label->stmt = stmt; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void GenerateIfNotTemp(ENode *enode, Object **objptr, CLabel **labelptr) { + Statement *stmt; + ENode *indnode; + + indnode = IRO_NewENode(EINDIRECT); + indnode->data.monadic = create_objectrefnode(*objptr); + if (!IS_TYPE_VOID(enode->rtype)) + indnode->rtype = enode->rtype; + else + indnode->rtype = enode->data.monadic->rtype; + + *labelptr = IRO_NewLabel(); + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_IFNGOTO; + stmt->expr = indnode; + stmt->label = *labelptr; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void GenerateNullcheckCondExpr(ENode *enode, Object **objptr) { + Statement *stmt; + ENode *indnode; + + indnode = IRO_NewENode(EINDIRECT); + indnode->data.monadic = create_objectrefnode(*objptr); + if (!IS_TYPE_VOID(enode->rtype)) + indnode->rtype = enode->rtype; + else + indnode->rtype = enode->data.nullcheck.nullcheckexpr->rtype; + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + stmt->expr = IRO_NewENode(EASS); + stmt->expr->data.diadic.left = indnode; + stmt->expr->data.diadic.right = enode->data.nullcheck.condexpr; + if (!IS_TYPE_VOID(enode->rtype)) + stmt->expr->rtype = enode->rtype; + else + stmt->expr->rtype = enode->data.nullcheck.nullcheckexpr->rtype; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void TransformLogicalAndLHS(ENode *enode, Object **objptr, CLabel **labelptr) { + Statement *stmt; + + *labelptr = IRO_NewLabel(); + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_IFNGOTO; + stmt->expr = enode->data.diadic.left; + stmt->label = *labelptr; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void TransformLogicalAndRHS(ENode *enode, Object **objptr, CLabel **labelptr) { + Statement *stmt; + ENode *indnode; + ENode *rightnode; + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_IFNGOTO; + stmt->expr = enode->data.diadic.right; + stmt->label = *labelptr; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; + + indnode = IRO_NewENode(EINDIRECT); + indnode->data.monadic = create_objectrefnode(*objptr); + if (!IS_TYPE_VOID(enode->rtype)) + indnode->rtype = enode->rtype; + else + CError_FATAL(1225); + + rightnode = IRO_NewENode(EINTCONST); + rightnode->data.intval = cint64_one; + rightnode->rtype = enode->rtype; + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + stmt->expr = IRO_NewENode(EASS); + stmt->expr->data.diadic.left = indnode; + stmt->expr->data.diadic.right = rightnode; + stmt->expr->rtype = enode->rtype; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_LABEL; + stmt->label = *labelptr; + stmt->label->stmt = stmt; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; + + enode->type = EINDIRECT; + enode->data.monadic = create_objectrefnode(*objptr); + CError_ASSERT(1276, !IS_TYPE_VOID(enode->rtype)); +} + +static void TransformLogicalOrLHS(ENode *enode, Object **objptr, CLabel **labelptr) { + Statement *stmt; + + *labelptr = IRO_NewLabel(); + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_IFGOTO; + stmt->expr = enode->data.diadic.left; + stmt->label = *labelptr; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; +} + +static void TransformLogicalOrRHS(ENode *enode, Object **objptr, CLabel **labelptr) { + Statement *stmt; + ENode *indnode; + ENode *rightnode; + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_IFGOTO; + stmt->expr = enode->data.diadic.right; + stmt->label = *labelptr; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; + + indnode = IRO_NewENode(EINDIRECT); + indnode->data.monadic = create_objectrefnode(*objptr); + if (!IS_TYPE_VOID(enode->rtype)) + indnode->rtype = enode->rtype; + else + CError_FATAL(1354); + + rightnode = IRO_NewENode(EINTCONST); + rightnode->data.intval = cint64_zero; + rightnode->rtype = enode->rtype; + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_EXPRESSION; + stmt->expr = IRO_NewENode(EASS); + stmt->expr->data.diadic.left = indnode; + stmt->expr->data.diadic.right = rightnode; + stmt->expr->rtype = enode->rtype; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; + + stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = ST_LABEL; + stmt->label = *labelptr; + stmt->label->stmt = stmt; + stmt->dobjstack = CurrStmt->dobjstack; + stmt->sourceoffset = CurrStmt->sourceoffset; + stmt->sourcefilepath = CurrStmt->sourcefilepath; + stmt->value = CurrStmt->value; + stmt->flags = CurrStmt->flags; + + if (PrevStmt) { + stmt->next = PrevStmt->next; + PrevStmt->next = stmt; + } else { + stmt->next = NULL; + } + PrevStmt = stmt; + + enode->type = EINDIRECT; + enode->data.monadic = create_objectrefnode(*objptr); + CError_ASSERT(1405, !IS_TYPE_VOID(enode->rtype)); +} + +static void LinearizeExpr1(ENode *a, ENode *b, Boolean flag, Boolean flag2) { + switch (a->type) { + ENODE_CASE_MONADIC: + LinearizeExpr1(a->data.monadic, a, 0, 0); + if (a->type == EFORCELOAD) { + Object *obj; + GenerateForceLoadTempAssignment(a, &obj); + a->type = EINDIRECT; + a->data.monadic = create_objectrefnode(obj); + CError_ASSERT(1428, !IS_TYPE_VOID(a->rtype)); + } + break; + ENODE_CASE_DIADIC_1: + case ECOMMA: + case EPMODULO: + case EROTL: + case EROTR: + case EBTST: + if (a->type == ECOMMA) { + LinearizeExpr1(a->data.diadic.left, a, 1, 0); + MakeLeftChildAsAssignment(a); + LinearizeExpr1(a->data.diadic.right, a, 0, 0); + AssignCommaRToTemp(a, flag); + } else if (a->data.diadic.right->cost >= a->data.diadic.left->cost) { + LinearizeExpr1(a->data.diadic.right, a, 0, 0); + LinearizeExpr1(a->data.diadic.left, a, 0, 0); + } else { + LinearizeExpr1(a->data.diadic.left, a, 0, 0); + LinearizeExpr1(a->data.diadic.right, a, 0, 0); + } + break; + ENODE_CASE_ASSIGN: + LinearizeExpr1(a->data.diadic.right, a, 0, 0); + LinearizeExpr1(a->data.diadic.left, a, 0, 0); + break; + case ELAND: + case ELOR: + if (a->type == ELAND) { + CLabel *label; + Object *obj; + CreateTempAssignmentToZero(a, &obj); + LinearizeExpr1(a->data.diadic.left, a, 0, 0); + TransformLogicalAndLHS(a, &obj, &label); + LinearizeExpr1(a->data.diadic.right, a, 0, 0); + TransformLogicalAndRHS(a, &obj, &label); + } else if (a->type == ELOR) { + CLabel *label; + Object *obj; + CreateTempAssignmentToOne(a, &obj); + LinearizeExpr1(a->data.diadic.left, a, 0, 0); + TransformLogicalOrLHS(a, &obj, &label); + LinearizeExpr1(a->data.diadic.right, a, 0, 0); + TransformLogicalOrRHS(a, &obj, &label); + } + break; + case ECOND: { + CLabel *label1, *label2; + Object *obj; + LinearizeExpr1(a->data.cond.cond, a, 0, 0); + GenerateCondExpression(a, &label1); + LinearizeExpr1(a->data.cond.expr1, a, 0, 0); + GenerateExpr1TempAssignment(a, &obj); + GenerateGoToStmt(a, &label2); + GenerateLabel(&label1); + LinearizeExpr1(a->data.cond.expr2, a, 0, 0); + GenerateExpr2TempAssignment(a, &obj); + GenerateLabel(&label2); + if (!IS_TYPE_VOID(a->rtype)) { + a->type = EINDIRECT; + a->data.monadic = create_objectrefnode(obj); + CError_ASSERT(1596, !IS_TYPE_VOID(a->rtype)); + } else { + a->type = EINTCONST; + a->data.intval = cint64_zero; + } + break; + } + case EPRECOMP: { + Object *temp = GetTempFromtheList(a); + a->type = EINDIRECT; + a->data.monadic = create_objectrefnode(temp); + CError_ASSERT(1614, !IS_TYPE_VOID(a->rtype)); + break; + } + case ENULLCHECK: { + CLabel *label; + Object *obj; + LinearizeExpr1(a->data.nullcheck.nullcheckexpr, a, 0, 0); + GenerateNullcheckExprTempAssignment(a, &obj); + GenerateIfNotTemp(a, &obj, &label); + LinearizeExpr1(a->data.nullcheck.condexpr, a, 0, 0); + GenerateNullcheckCondExpr(a, &obj); + GenerateLabel(&label); + if (!IS_TYPE_VOID(a->rtype)) { + a->type = EINDIRECT; + a->data.monadic = create_objectrefnode(obj); + CError_ASSERT(1639, !IS_TYPE_VOID(a->rtype)); + } else { + a->type = EINTCONST; + a->data.intval = cint64_zero; + } + break; + } + case EFUNCCALL: + case EFUNCCALLP: { + SInt32 count; + SInt32 i; + ENodeList *list; + ENode **arr; + SInt16 *arr2; + + IRO_IsLeafFunction = 0; + + list = a->data.funccall.args; + count = 0; + while (list) { + list = list->next; + count++; + } + + if (count) { + arr = oalloc(sizeof(ENode *) * count); + list = a->data.funccall.args; + count = 0; + while (list) { + arr[count] = list->node; + list = list->next; + count++; + } + + arr2 = oalloc(sizeof(SInt16) * count); + for (i = 0; i < count; i++) + arr2[i] = count - i - 1; + + for (i = 0; i < count; i++) + LinearizeExpr1(arr[arr2[i]], a, 0, 0); + } + + LinearizeExpr1(a->data.funccall.funcref, a, 0, 0); + break; + } + + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case ESETCONST: + case EVECTOR128CONST: + break; + + default: + CError_FATAL(1723); + } +} + +static IROLinear *LinearizeExpr(ENode *enode) { + IROLinear *linear = NULL; + + switch (enode->type) { + ENODE_CASE_MONADIC: + linear = IRO_NewLinear(IROLinearOp1Arg); + linear->u.monadic = LinearizeExpr(enode->data.monadic); + linear->nodetype = enode->type; + linear->rtype = enode->rtype; + linear->nodeflags = enode->flags; + if (IRO_IsAssignOp[linear->nodetype]) + MarkAssigned(linear->u.monadic, 1); + if (linear->nodetype == EINDIRECT) { + MarkSubs1(linear->u.monadic); + linear->u.monadic->flags |= IROLF_Immind | IROLF_Ind; + if (IS_LINEAR_DIADIC(linear->u.monadic, EADD)) + MarkSubscript(linear->u.monadic); + } + break; + ENODE_CASE_DIADIC_1: + case ECOMMA: + case EPMODULO: + case EROTL: + case EROTR: + case EBTST: + linear = IRO_NewLinear(IROLinearOp2Arg); + linear->nodeflags = enode->flags; + if (!ENODE_IS(enode, ECOMMA) && enode->data.diadic.right->cost >= enode->data.diadic.left->cost) { + linear->u.diadic.right = LinearizeExpr(enode->data.diadic.right); + linear->u.diadic.left = LinearizeExpr(enode->data.diadic.left); + linear->flags |= IROLF_8000; + } else { + linear->u.diadic.left = LinearizeExpr(enode->data.diadic.left); + linear->u.diadic.right = LinearizeExpr(enode->data.diadic.right); + } + linear->nodetype = enode->type; + linear->rtype = enode->rtype; + if (IRO_IsAssignOp[linear->nodetype]) + MarkAssigned(linear->u.diadic.left, IRO_IsModifyOp[linear->nodetype]); + break; + ENODE_CASE_ASSIGN: + linear = IRO_NewLinear(IROLinearOp2Arg); + linear->nodeflags = enode->flags; + linear->u.diadic.right = LinearizeExpr(enode->data.diadic.right); + linear->u.diadic.left = LinearizeExpr(enode->data.diadic.left); + linear->flags |= IROLF_8000; + linear->nodetype = enode->type; + linear->rtype = enode->rtype; + MarkAssigned(linear->u.diadic.left, IRO_IsModifyOp[linear->nodetype]); + break; + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EVECTOR128CONST: + linear = IRO_NewLinear(IROLinearOperand); + linear->nodeflags = enode->flags; + linear->u.node = enode; + linear->rtype = enode->rtype; + break; + case EFUNCCALL: + case EFUNCCALLP: { + SInt32 count; + SInt32 i; + ENodeList *list; + ENode **arr; + SInt16 *arr2; + + linear = IRO_NewLinear(IROLinearFunccall); + linear->nodeflags = enode->flags; + linear->u.funccall.ispascal = enode->type == EFUNCCALLP; + + list = enode->data.funccall.args; + count = 0; + while (list) { + list = list->next; + count++; + } + + arr = NULL; + if (count) { + arr = oalloc(sizeof(ENode *) * count); + list = enode->data.funccall.args; + count = 0; + while (list) { + arr[count] = list->node; + list = list->next; + count++; + } + + arr2 = oalloc(sizeof(SInt16) * count); + for (i = 0; i < count; i++) + arr2[i] = count - i - 1; + + for (i = 0; i < count; i++) { + arr[arr2[i]] = (ENode *) LinearizeExpr(arr[arr2[i]]); + MarkArgs((IROLinear *) arr[arr2[i]]); + } + } + + linear->u.funccall.argCount = count; + linear->u.funccall.args = (IROLinear **) arr; + linear->u.funccall.linear8 = LinearizeExpr(enode->data.funccall.funcref); + linear->u.funccall.functype = enode->data.funccall.functype; + linear->rtype = enode->rtype; + break; + } + default: + CError_FATAL(1943); + } + + if (linear) + LinkLinear(linear); + return linear; +} + +void IRO_PreLinearize(Statement *stmt) { + IRO_FirstLinear = IRO_LastLinear = NULL; + IRO_NumLinear = 0; + CurrStmt = PrevStmt = NULL; + + while (stmt) { + CurStat = stmt; + CurrStmt = stmt; + NullCheckList = NULL; + + switch (stmt->type) { + case ST_NOP: + case ST_LABEL: + case ST_GOTO: + break; + case ST_OVF: + CError_FATAL(1989); + case ST_EXPRESSION: + LinearizeExpr1(stmt->expr, NULL, 0, 0); + break; + case ST_SWITCH: + LinearizeExpr1(stmt->expr, NULL, 0, 0); + break; + case ST_IFGOTO: + LinearizeExpr1(stmt->expr, NULL, 0, 0); + break; + case ST_IFNGOTO: + LinearizeExpr1(stmt->expr, NULL, 0, 0); + break; + case ST_RETURN: + if (stmt->expr) + LinearizeExpr1(stmt->expr, NULL, 0, 0); + break; + case ST_BEGINCATCH: + LinearizeExpr1(stmt->expr, NULL, 0, 0); + break; + case ST_ENDCATCH: + LinearizeExpr1(stmt->expr, NULL, 0, 0); + break; + case ST_ENDCATCHDTOR: + LinearizeExpr1(stmt->expr, NULL, 0, 0); + break; + + case ST_EXIT: + case ST_ENTRY: + case ST_ASM: + break; + + default: + CError_FATAL(2038); + } + + PrevStmt = stmt; + stmt = stmt->next; + } + + IRO_CheckForUserBreak(); +} + +static void MarkAllSubExprs(IROLinear *linear) { + IROLinear *scan; + int i; + + for (scan = linear; scan; scan = scan->next) + scan->flags &= ~IROLF_Reffed; + + for (scan = linear; scan; scan = scan->next) + MarkSubExpr(scan); +} + +void IRO_Linearize(Statement *stmt) { + IROLinear *linear; + + IRO_FirstLinear = IRO_LastLinear = NULL; + IRO_NumLinear = 0; + + while (stmt) { + CurStat = stmt; + linear = NULL; + + switch (stmt->type) { + case ST_NOP: + linear = IRO_NewLinear(IROLinearNop); + break; + case ST_LABEL: + linear = IRO_NewLinear(IROLinearLabel); + linear->u.label.label = stmt->label; + linear->flags |= IROLF_1; + break; + case ST_GOTO: + linear = IRO_NewLinear(IROLinearGoto); + linear->u.label.label = stmt->label; + break; + case ST_EXPRESSION: + LinearizeExpr(stmt->expr); + break; + case ST_SWITCH: + linear = IRO_NewLinear(IROLinearSwitch); + linear->u.swtch.x4 = LinearizeExpr(stmt->expr); + linear->u.swtch.info = (SwitchInfo *) stmt->label; + break; + case ST_IFGOTO: + linear = IRO_NewLinear(IROLinearIf); + linear->u.label.x4 = LinearizeExpr(stmt->expr); + linear->u.label.label = stmt->label; + break; + case ST_IFNGOTO: + linear = IRO_NewLinear(IROLinearIfNot); + linear->u.label.x4 = LinearizeExpr(stmt->expr); + linear->u.label.label = stmt->label; + break; + case ST_RETURN: + IRO_FunctionHasReturn = 1; + linear = IRO_NewLinear(IROLinearReturn); + if (stmt->expr) + linear->u.monadic = LinearizeExpr(stmt->expr); + else + linear->u.monadic = NULL; + break; + case ST_OVF: + CError_FATAL(2143); + break; + case ST_EXIT: + linear = IRO_NewLinear(IROLinearExit); + linear->u.label.label = stmt->label; + break; + case ST_ENTRY: + linear = IRO_NewLinear(IROLinearEntry); + linear->u.label.label = stmt->label; + linear->flags |= IROLF_1; + break; + case ST_BEGINCATCH: + linear = IRO_NewLinear(IROLinearBeginCatch); + linear->u.ctch.linear = LinearizeExpr(stmt->expr); + linear->u.ctch.x4 = 0; + linear->u.ctch.x8 = 0; + break; + case ST_ENDCATCH: + linear = IRO_NewLinear(IROLinearEndCatch); + linear->u.monadic = LinearizeExpr(stmt->expr); + break; + case ST_ENDCATCHDTOR: + linear = IRO_NewLinear(IROLinearEndCatchDtor); + linear->u.monadic = LinearizeExpr(stmt->expr); + break; + case ST_ASM: + linear = IRO_NewLinear(IROLinearAsm); + linear->u.asm_stmt = stmt; + if (copts.optimizewithasm) { + IAEffects effects; + CodeGen_GetAsmEffects(stmt, &effects); + if (effects.x0 || effects.x3) + DisableDueToAsm = 1; + } else { + DisableDueToAsm = 1; + } + break; + default: + CError_FATAL(2194); + } + + if (linear) + LinkLinear(linear); + stmt = stmt->next; + } + + linear = IRO_NewLinear(IROLinearEnd); + linear->flags |= IROLF_1; + LinkLinear(linear); + + MarkAllSubExprs(IRO_FirstLinear); + IRO_CheckForUserBreak(); +} + +static Statement *NewStatement(IROLinear *linear, StatementType sttype) { + Statement *stmt = lalloc(sizeof(Statement)); + memset(stmt, 0, sizeof(Statement)); + stmt->type = sttype; + stmt->value = 1; + if (linear->stmt) { + stmt->dobjstack = linear->stmt->dobjstack; + stmt->sourceoffset = linear->stmt->sourceoffset; + stmt->sourcefilepath = linear->stmt->sourcefilepath; + stmt->value = linear->stmt->value; + stmt->flags = linear->stmt->flags; + } else { + stmt->sourceoffset = -1; + stmt->sourcefilepath = NULL; + } + return stmt; +} + +ENode *IRO_NewENode(ENodeType nodetype) { + ENode *enode = lalloc(sizeof(ENode)); + memset(enode, 0, sizeof(ENode)); + enode->type = nodetype; + return enode; +} + +static ENode *BuildExpr(IROLinear *linear) { + ENode *enode; + + switch (linear->type) { + case IROLinearOperand: + enode = IRO_NewENode(linear->u.node->type); + enode->flags = linear->nodeflags; + *enode = *linear->u.node; + break; + case IROLinearOp1Arg: + enode = IRO_NewENode(linear->nodetype); + enode->flags = linear->nodeflags; + enode->data.monadic = BuildExpr(linear->u.monadic); + enode->rtype = linear->rtype; + enode->cost = enode->data.monadic->cost; + if (!enode->cost) + enode->cost = 1; + break; + case IROLinearOp2Arg: + enode = IRO_NewENode(linear->nodetype); + enode->flags = linear->nodeflags; + enode->data.diadic.left = BuildExpr(linear->u.diadic.left); + enode->data.diadic.right = BuildExpr(linear->u.diadic.right); + + enode->cost = enode->data.diadic.left->cost; + if (enode->data.diadic.right->cost > enode->cost) + enode->cost = enode->data.diadic.right->cost; + else if (enode->data.diadic.right->cost == enode->cost) + enode->cost += 1; + + if (ENODE_IS4(enode, ESHL, ESHR, EDIV, EMODULO)) + enode->cost += 2; + if (enode->cost > 200) + enode->cost = 200; + + enode->rtype = linear->rtype; + break; + case IROLinearOp3Arg: + enode = IRO_NewENode(linear->nodetype); + enode->flags = linear->nodeflags; + enode->data.cond.cond = BuildExpr(linear->u.args3.a); + enode->data.cond.expr1 = BuildExpr(linear->u.args3.b); + enode->data.cond.expr2 = BuildExpr(linear->u.args3.c); + enode->rtype = linear->rtype; + + enode->cost = enode->data.cond.cond->cost; + if (enode->data.cond.expr1->cost > enode->cost) + enode->cost = enode->data.cond.expr1->cost; + if (enode->data.cond.expr2->cost > enode->cost) + enode->cost = enode->data.cond.expr2->cost; + enode->cost += 1; + + if (enode->cost > 200) + enode->cost = 200; + + break; + + case IROLinearFunccall: { + int i; + enode = IRO_NewENode(linear->u.funccall.ispascal ? EFUNCCALLP : EFUNCCALL); + enode->flags = linear->nodeflags; + enode->data.funccall.funcref = BuildExpr(linear->u.funccall.linear8); + enode->data.funccall.functype = linear->u.funccall.functype; + enode->data.funccall.args = NULL; + enode->cost = 200; + for (i = linear->u.funccall.argCount - 1; i >= 0; i--) { + ENodeList *list = lalloc(sizeof(ENodeList)); + list->node = BuildExpr(linear->u.funccall.args[i]); + list->next = enode->data.funccall.args; + enode->data.funccall.args = list; + } + enode->rtype = linear->rtype; + break; + } + + default: + IRO_Dump("Oh, oh, bad expression type in BuildExpr at: %d\n", linear->index); + CError_FATAL(2390); + } + + enode->pointsTo = linear->pointsToFunction; + return enode; +} + +Statement *IRO_Delinearize(IRONode *node, IROLinear *linear) { + IROLinear *scanlin; + Statement *firstStmt; + Statement *lastStmt; + IRONode *scan; + Statement *stmt; + IRONode mynode; + + firstStmt = lastStmt = NULL; + + if (node) { + scan = node; + MarkAllSubExprs(IRO_FirstLinear); + } else { + memset(&mynode, 0, sizeof(IRONode)); + mynode.first = linear; + scan = &mynode; + MarkAllSubExprs(linear); + } + + while (scan) { + for (scanlin = scan->first; scanlin; scanlin = scanlin->next) { + stmt = NULL; + if (!(scanlin->flags & IROLF_Reffed)) { + switch (scanlin->type) { + case IROLinearNop: + if (scan == node) + stmt = NewStatement(scanlin, ST_NOP); + else + stmt = NULL; + break; + case IROLinearOperand: + case IROLinearOp1Arg: + case IROLinearOp2Arg: + case IROLinearOp3Arg: + case IROLinearFunccall: + stmt = NewStatement(scanlin, ST_EXPRESSION); + stmt->expr = BuildExpr(scanlin); + break; + case IROLinearGoto: + stmt = NewStatement(scanlin, ST_GOTO); + stmt->label = scanlin->u.label.label; + break; + case IROLinearExit: + stmt = NewStatement(scanlin, ST_EXIT); + stmt->label = scanlin->u.label.label; + break; + case IROLinearIf: + case IROLinearIfNot: + stmt = NewStatement(scanlin, (scanlin->type == IROLinearIf) ? ST_IFGOTO : ST_IFNGOTO); + stmt->label = scanlin->u.label.label; + stmt->expr = BuildExpr(scanlin->u.label.x4); + break; + case IROLinearReturn: + stmt = NewStatement(scanlin, ST_RETURN); + if (scanlin->u.monadic) + stmt->expr = BuildExpr(scanlin->u.monadic); + break; + case IROLinearLabel: + stmt = NewStatement(scanlin, ST_LABEL); + stmt->label = scanlin->u.label.label; + stmt->label->stmt = stmt; + break; + case IROLinearEntry: + stmt = NewStatement(scanlin, ST_ENTRY); + stmt->label = scanlin->u.label.label; + stmt->label->stmt = stmt; + break; + case IROLinearSwitch: + stmt = NewStatement(scanlin, ST_SWITCH); + stmt->expr = BuildExpr(scanlin->u.swtch.x4); + stmt->label = (CLabel *) scanlin->u.swtch.info; + break; + case IROLinearBeginCatch: + stmt = NewStatement(scanlin, ST_BEGINCATCH); + stmt->expr = BuildExpr(scanlin->u.ctch.linear); + break; + case IROLinearEndCatch: + stmt = NewStatement(scanlin, ST_ENDCATCH); + stmt->expr = BuildExpr(scanlin->u.monadic); + break; + case IROLinearEndCatchDtor: + stmt = NewStatement(scanlin, ST_ENDCATCHDTOR); + stmt->expr = BuildExpr(scanlin->u.monadic); + break; + case IROLinearAsm: + stmt = scanlin->u.asm_stmt; + break; + case IROLinearEnd: + stmt = NULL; + break; + default: + CError_FATAL(2685); + } + + if (stmt) { + if (LoopOptimizerRun) { + SInt32 i; + SInt32 value = 1; + for (i = 0; i < scan->loopdepth; i++) { + value = (value < 4096) ? (value * 8) : (value + 1); + } + stmt->value = value; + } + if (firstStmt) + lastStmt->next = stmt; + else + firstStmt = stmt; + lastStmt = stmt; + } + } + if (scanlin == scan->last) + break; + } + scan = scan->nextnode; + } + + return firstStmt; +} + +void IRO_RenumberInts(void) { + IROLinear *linear = IRO_FirstLinear; + IRO_NumLinear = 0; + while (linear) { + linear->index = IRO_NumLinear++; + linear = linear->next; + } +} + +static void TravExprToUpdateFlags(IROLinear *linear) { + int i; + + linear->flags &= ~(IROLF_Assigned | IROLF_8 | IROLF_Used | IROLF_Ind | IROLF_Subs | IROLF_LoopInvariant | IROLF_Ris | IROLF_Immind | IROLF_CouldError); + switch (linear->type) { + case IROLinearNop: + case IROLinearOperand: + break; + case IROLinearOp1Arg: + TravExprToUpdateFlags(linear->u.monadic); + if (IRO_IsAssignOp[linear->nodetype]) + MarkAssigned(linear->u.monadic, 1); + if (linear->nodetype == EINDIRECT) { + MarkSubs1(linear->u.monadic); + linear->u.monadic->flags |= IROLF_Immind | IROLF_Ind; + if (IS_LINEAR_DIADIC(linear->u.monadic, EADD)) + MarkSubscript(linear->u.monadic); + } + break; + case IROLinearOp2Arg: + TravExprToUpdateFlags(linear->u.diadic.left); + TravExprToUpdateFlags(linear->u.diadic.right); + if (IRO_IsAssignOp[linear->nodetype]) + MarkAssigned(linear->u.diadic.left, IRO_IsModifyOp[linear->nodetype]); + break; + case IROLinearOp3Arg: + TravExprToUpdateFlags(linear->u.args3.a); + TravExprToUpdateFlags(linear->u.args3.b); + TravExprToUpdateFlags(linear->u.args3.c); + break; + case IROLinearFunccall: + TravExprToUpdateFlags(linear->u.funccall.linear8); + for (i = linear->u.funccall.argCount - 1; i >= 0; i--) + TravExprToUpdateFlags(linear->u.funccall.args[i]); + break; + default: + IRO_Dump("Oh, oh, bad expression type in TravExprToUpdateFlags at: %d\n", linear->index); + CError_FATAL(2853); + } +} + +void IRO_UpdateFlagsOnInts(void) { + IROLinear *linear; + IRONode *node; + + MarkAllSubExprs(IRO_FirstLinear); + + for (node = IRO_FirstNode; node; node = node->nextnode) { + for (linear = node->first; linear; linear = linear->next) { + if (!(linear->flags & IROLF_Reffed)) { + switch (linear->type) { + case IROLinearOperand: + case IROLinearOp1Arg: + case IROLinearOp2Arg: + case IROLinearOp3Arg: + case IROLinearFunccall: + TravExprToUpdateFlags(linear); + break; + case IROLinearIf: + case IROLinearIfNot: + TravExprToUpdateFlags(linear->u.label.x4); + break; + case IROLinearReturn: + if (linear->u.monadic) + TravExprToUpdateFlags(linear->u.monadic); + break; + case IROLinearSwitch: + TravExprToUpdateFlags(linear->u.swtch.x4); + break; + case IROLinearBeginCatch: + TravExprToUpdateFlags(linear->u.ctch.linear); + break; + case IROLinearEndCatch: + TravExprToUpdateFlags(linear->u.monadic); + break; + case IROLinearEndCatchDtor: + TravExprToUpdateFlags(linear->u.monadic); + break; + case IROLinearNop: + case IROLinearGoto: + case IROLinearLabel: + case IROLinearEntry: + case IROLinearExit: + case IROLinearAsm: + case IROLinearEnd: + break; + default: + CError_FATAL(2931); + } + } + if (linear == node->last) + break; + } + } +} + +void IRO_SaveLinearIR(IROLinearIRSave *save) { + save->firstLinear = IRO_FirstLinear; + save->lastLinear = IRO_LastLinear; + save->numLinear = IRO_NumLinear; + save->curStat = CurStat; + save->disableDueToAsm = DisableDueToAsm; + save->isLeafFunction = IRO_IsLeafFunction; + save->functionHasReturn = IRO_FunctionHasReturn; + save->nullCheckList = NullCheckList; + save->currStmt = CurrStmt; + save->prevStmt = PrevStmt; +} + +void IRO_RestoreLinearIR(IROLinearIRSave *save) { + IRO_FirstLinear = save->firstLinear; + IRO_LastLinear = save->lastLinear; + IRO_NumLinear = save->numLinear; + CurStat = save->curStat; + DisableDueToAsm = save->disableDueToAsm; + IRO_IsLeafFunction = save->isLeafFunction; + IRO_FunctionHasReturn = save->functionHasReturn; + NullCheckList = save->nullCheckList; + CurrStmt = save->currStmt; + PrevStmt = save->prevStmt; +} + diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.h b/compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.h new file mode 100644 index 0000000..c0b2d17 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.h @@ -0,0 +1,165 @@ +#ifndef COMPILER_IROLINEARFORM_H +#define COMPILER_IROLINEARFORM_H + +#include "IrOptimizer.h" +#include "compiler/Switch.h" +#include "compiler/enode.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif + +typedef struct IROLinearIRSave { + IROLinear *firstLinear; + IROLinear *lastLinear; + UInt32 numLinear; + Statement *curStat; + Boolean disableDueToAsm; + Boolean isLeafFunction; + Boolean functionHasReturn; + void *nullCheckList; + Statement *currStmt; + Statement *prevStmt; +} IROLinearIRSave; + +typedef enum IROLinearType { + IROLinearNop, + IROLinearOperand, + IROLinearOp1Arg, + IROLinearOp2Arg, + IROLinearGoto, + IROLinearIf, + IROLinearIfNot, + IROLinearReturn, + IROLinearLabel, + IROLinearSwitch, + IROLinearOp3Arg, + IROLinearFunccall, + IROLinearEntry, + IROLinearExit, + IROLinearBeginCatch, + IROLinearEndCatch, + IROLinearEndCatchDtor, + IROLinearAsm, + IROLinear18, + IROLinear19, + IROLinearEnd +} IROLinearType; + +enum { + IROLF_1 = 0x1, + IROLF_Reffed = 0x2, + IROLF_Assigned = 0x4, + IROLF_8 = 0x8, + IROLF_Used = 0x10, + IROLF_Ind = 0x20, + IROLF_Subs = 0x40, + IROLF_80 = 0x80, + IROLF_LoopInvariant = 0x100, + IROLF_BeginLoop = 0x200, + IROLF_EndLoop = 0x400, + IROLF_Ris = 0x800, + IROLF_Immind = 0x1000, + IROLF_VecOp = 0x2000, + IROLF_4000 = 0x4000, + IROLF_8000 = 0x8000, + IROLF_VecOpBase = 0x10000, + IROLF_20000 = 0x20000, + IROLF_CounterLoop = 0x40000, + IROLF_BitfieldIndirect = 0x80000, + IROLF_CouldError = 0x100000 +}; + +// actual name is LinearNode as per mwccppc v8 +struct IROLinear { + IROLinearType type; + ENodeType nodetype; + SInt32 flags; + UInt16 nodeflags; + unsigned short index; + Statement *stmt; + Type *rtype; + IROExpr *expr; + struct ERange *x16; + PointsToFunction *pointsToFunction; + Boolean x1E; + union { + struct { + void *data1; + void *data2; + void *data3; + void *data4; + void *data5; + } idk; + // Operand + ENode *node; + // Op1Arg + IROLinear *monadic; + // Op2Arg + struct { + IROLinear *left; + IROLinear *right; + } diadic; + // Op3Arg + struct { + IROLinear *a; + IROLinear *b; + IROLinear *c; + } args3; + // Funccall + struct { + char ispascal; + short argCount; + IROLinear **args; + IROLinear *linear8; // funcref + TypeFunc *functype; + struct LocationSetSet *returnedLocs; + } funccall; + // Asm + Statement *asm_stmt; + // If, IfNot, Goto, Label + struct { + CLabel *label; + IROLinear *x4; // if,ifnot only?? + } label; + struct { + SwitchInfo *info; + IROLinear *x4; + } swtch; + // BeginCatch, EndCatch, EndCatchDtor + struct { + IROLinear *linear; + int x4; + int x8; + } ctch; + } u; + IROLinear *next; +}; + +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +extern IROLinear *IRO_FirstLinear; +extern IROLinear *IRO_LastLinear; +extern UInt32 IRO_NumLinear; +extern Statement *CurStat; + +extern IROLinear *IRO_NewLinear(IROLinearType type); +extern void IRO_PreLinearize(Statement *stmt); +extern void IRO_Linearize(Statement *stmt); +extern ENode *IRO_NewENode(ENodeType nodetype); +extern Statement *IRO_Delinearize(IRONode *node, IROLinear *linear); +extern void IRO_RenumberInts(void); +extern void IRO_UpdateFlagsOnInts(void); +extern void IRO_SaveLinearIR(IROLinearIRSave *save); +extern void IRO_RestoreLinearIR(IROLinearIRSave *save); + +#define IS_LINEAR_ENODE(_linear, _nodetype) ( ((_linear)->type == IROLinearOperand) && ((_linear)->u.node->type) == (_nodetype) ) +#define IS_LINEAR_MONADIC(_linear, _nodetype) ( ((_linear)->type == IROLinearOp1Arg) && ((_linear)->nodetype) == (_nodetype) ) +#define IS_LINEAR_MONADIC_2(_linear, _nodetype1, _nodetype2) ( ((_linear)->type == IROLinearOp1Arg) && (((_linear)->nodetype) == (_nodetype1) || ((_linear)->nodetype) == (_nodetype2)) ) +#define IS_LINEAR_DIADIC(_linear, _nodetype) ( ((_linear)->type == IROLinearOp2Arg) && ((_linear)->nodetype) == (_nodetype) ) +#define IS_LINEAR_DIADIC_2(_linear, _nodetype1, _nodetype2) ( ((_linear)->type == IROLinearOp2Arg) && (((_linear)->nodetype) == (_nodetype1) || ((_linear)->nodetype) == (_nodetype2)) ) +#define IS_LINEAR_DIADIC_3(_linear, _nodetype1, _nodetype2, _nodetype3) ( ((_linear)->type == IROLinearOp2Arg) && (((_linear)->nodetype) == (_nodetype1) || ((_linear)->nodetype) == (_nodetype2) || ((_linear)->nodetype) == (_nodetype3)) ) + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroLoop.c b/compiler_and_linker/FrontEnd/Optimizer/IroLoop.c new file mode 100644 index 0000000..850146d --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroLoop.c @@ -0,0 +1,2324 @@ +#include "IroLoop.h" +#include "IroCSE.h" +#include "IroDump.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroPropagate.h" +#include "IroSubable.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/CFunc.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/objects.h" +#include "compiler/types.h" + +IRONode *LoopNode; +Boolean ConditionalHeaderAtBottom; +IROLoopInd *FirstInd; +BitVector *InLoop; +IROList IRO_InitLList; +BitVector *InLoop_Exits; +BitVector *InLoop_Tails; +UInt32 LoopExitNumber; +UInt32 LoopTailNum; +IRONode *LoopExitSuccessor; +IRONode *LoopTail; +IROLoopMemRef *IRO_LoopMemRefFirst; +IROLoopMemRef *IRO_LoopMemRefCurrent; +static IROExpr *RisList; +static BitVector *AllKills; +static Boolean KnownBounds; +static SInt32 Times; +static IROLinear *PredInt; +static IROElmList *FirstAddendLinear; +static IROElmList *LastAddendLinear; +static int NoSubableSubs; + +// forward decls +static void MyHandleLoop_Vector(IRONode *fnode); +static void MyHandleLoop_Motion(IRONode *fnode); +static void CheckAllLoopAddresses(IRONode *fnode, BitVector *bv, Boolean *resultFlag); +static void MakeLoopEntry(IROLinear *nd, IROAddrRecord *rec, Boolean mustreach1, Boolean flag2); +static void MoveInvarianceInAddressExpr(void); +static IROLinear *RearrangeInvarianceInAddressExpr(IROLinear *nd, IROList *list); +static UInt32 IsAssignmentReductionCandidate(IROLinear *nd); + +void FindMustReach(void) { + IRONode *fnode; + IRONode *fnode2; + IRONode *pred; + int i; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + fnode->mustreach = 0; + if (Bv_IsBitSet(fnode->index, InLoop)) { + fnode->mustreach = 1; + + for (i = 0; i < LoopNode->numpred; i++) { + pred = IRO_NodeTable[LoopNode->pred[i]]; + if (Bv_IsBitSet(pred->index, InLoop) && !Bv_IsBitSet(fnode->index, pred->dom)) { + fnode->mustreach = 0; + break; + } + } + + for (fnode2 = IRO_FirstNode; fnode2; fnode2 = fnode2->nextnode) { + if (Bv_IsBitSet(fnode2->index, InLoop)) { + for (i = 0; i < fnode2->numsucc; i++) { + if (!Bv_IsBitSet(fnode2->succ[i], InLoop) && !Bv_IsBitSet(fnode->index, fnode2->dom)) { + fnode->mustreach = 0; + break; + } + } + + if (!fnode->mustreach) + break; + } + } + } + } +} + +void FindMustReach1(IRONode *checkfnode) { + IRONode *fnode; + IRONode *fnode2; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop)) { + fnode->mustreach1 = 1; + for (fnode2 = IRO_FirstNode; fnode2; fnode2 = fnode2->nextnode) { + if (Bv_IsBitSet(fnode2->index, InLoop)) { + if (Bv_IsBitSet(fnode2->index, InLoop_Tails) && !Bv_IsBitSet(fnode->index, fnode2->dom)) + fnode->mustreach1 = 0; + + if (Bv_IsBitSet(fnode2->index, InLoop_Exits) && fnode2 != checkfnode && !Bv_IsBitSet(fnode->index, fnode2->dom)) + fnode->mustreach1 = 0; + + if (!fnode->mustreach1) + break; + } + } + } + } +} + +static void IRO_FindLoopTailsAndExits(IRONode *fnode) { + IRONode *scan; + IRONode *succ; + int i; + + for (scan = IRO_FirstNode; scan; scan = scan->nextnode) { + if (Bv_IsBitSet(scan->index, InLoop)) { + for (i = 0; i < scan->numsucc; i++) { + succ = IRO_NodeTable[scan->succ[i]]; + if (succ == fnode) { + Bv_SetBit(scan->index, InLoop_Tails); + LoopTail = scan; + LoopTailNum++; + } + if (!Bv_IsBitSet(succ->index, InLoop)) { + LoopExitNumber++; + LoopExitSuccessor = succ; + Bv_SetBit(scan->index, InLoop_Exits); + } + } + } + } + + IRO_Dump("IRO_FindLoopTailsAndExits:For header %d, Loop exits and loop tails are \n", fnode->index); + IRO_DumpBits("Loop Exits: ", InLoop_Exits); + IRO_DumpBits("Loop Tails: ", InLoop_Tails); + IRO_Dump("LoopExitNum=%d: \n", LoopExitNumber); + if (LoopExitSuccessor) + IRO_Dump("LoopExitSuccessor node =%d: \n", LoopExitSuccessor->index); +} + +static int IsSafeTypcon(IROLinear *nd) { + Type *srcType; + Type *destType; + SInt32 srcSize; + SInt32 destSize; + Boolean srcUnsigned; + Boolean destUnsigned; + + srcType = nd->u.monadic->rtype; + destType = nd->rtype; + if (!IS_TYPE_INT(srcType) || !IS_TYPE_INT(destType)) + return 0; + + srcSize = srcType->size; + destSize = destType->size; + srcUnsigned = IRO_IsUnsignedType(srcType); + destUnsigned = IRO_IsUnsignedType(destType); + + if (srcUnsigned == destUnsigned && destSize >= srcSize) + return 1; + if (srcUnsigned == 1 && destUnsigned == 0 && destSize > srcSize) + return 1; + return 0; +} + +static int Reducable(IROLinear *nd, IROLinear **resultNd1, IROLinear **resultNd2, VarRecord **resultVar) { + IROLinear *indirect; + IROLinear *left; + IROLinear *right; + Boolean leftInvariant; + Boolean rightInvariant; + Boolean leftTypcon; + Boolean rightTypcon; + Object *obj; + ENode *enode; + IROLoopInd *ind; + CInt64 val64; + SInt32 val; + SInt32 div; + + leftInvariant = 0; + rightInvariant = 0; + leftTypcon = 0; + rightTypcon = 0; + + if (nd->type == IROLinearOp2Arg && nd->nodetype == EADD && (IS_TYPE_INT(nd->rtype) || IS_TYPE_POINTER_ONLY(nd->rtype))) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + if (left->type == IROLinearOp1Arg && left->nodetype == ETYPCON) { + leftTypcon = 1; + leftInvariant = (left->flags & IROLF_LoopInvariant) != 0; + left = left->u.monadic; + } + if (right->type == IROLinearOp1Arg && right->nodetype == ETYPCON) { + rightTypcon = 1; + rightInvariant = (right->flags & IROLF_LoopInvariant) != 0; + right = right->u.monadic; + } + + if (((left->flags & IROLF_LoopInvariant) || leftInvariant) && IRO_IsVariable(right)) { + if (leftInvariant || ((!(obj = IRO_IsVariable(left)) || !IRO_IsRegable(obj)) && !IRO_IsConstant(left))) { + if ( + left->type == IROLinearOp2Arg && + left->nodetype == EADD && + (obj = IRO_IsVariable(left->u.diadic.left)) && + IRO_IsRegable(obj) && + IRO_IsConstant(left->u.diadic.right) + ) + return 0; + + if (rightTypcon) { + if (!IsSafeTypcon(nd->u.diadic.right)) + return 0; + *resultNd2 = nd->u.diadic.right; + } else { + *resultNd2 = right; + } + + indirect = right; + *resultNd1 = IRO_NewLinear(IROLinearOperand); + + enode = IRO_NewENode(EINTCONST); + enode->data.intval = cint64_one; + enode->rtype = nd->u.diadic.right->rtype; + (*resultNd1)->rtype = nd->u.diadic.right->rtype; + (*resultNd1)->u.node = enode; + } else { + return 0; + } + } else if ( + ((left->flags & IROLF_LoopInvariant) || leftInvariant) && + right->type == IROLinearOp2Arg && + !rightTypcon && + (right->nodetype == EMUL || right->nodetype == ESHL) + ) { + if (IRO_IsConstant(right->u.diadic.right)) { + if (right->nodetype == ESHL) { + right->nodetype = EMUL; + right->u.diadic.right->u.node->data.intval = CInt64_Shl(cint64_one, right->u.diadic.right->u.node->data.intval); + } + if (right->u.diadic.left->type == IROLinearOp1Arg) { + if (IRO_IsVariable(right->u.diadic.left)) { + *resultNd2 = right->u.diadic.left; + indirect = right->u.diadic.left; + *resultNd1 = right->u.diadic.right; + } else if (right->u.diadic.left->nodetype == ETYPCON && IRO_IsVariable(right->u.diadic.left->u.monadic)) { + if (!IsSafeTypcon(right->u.diadic.left)) + return 0; + *resultNd2 = right->u.diadic.left; + indirect = right->u.diadic.left->u.monadic; + *resultNd1 = right->u.diadic.right; + } else { + return 0; + } + } else { + return 0; + } + } else { + return 0; + } + } else if ( + ((right->flags & IROLF_LoopInvariant) || rightInvariant) && + left->type == IROLinearOp2Arg && + !leftTypcon && + (left->nodetype == EMUL || left->nodetype == ESHL) + ) { + if (IRO_IsConstant(left->u.diadic.right)) { + if (left->nodetype == ESHL) { + left->nodetype = EMUL; + left->u.diadic.right->u.node->data.intval = CInt64_Shl(cint64_one, left->u.diadic.right->u.node->data.intval); + } + if (left->u.diadic.left->type == IROLinearOp1Arg) { + if (IRO_IsVariable(left->u.diadic.left)) { + *resultNd2 = left->u.diadic.left; + indirect = left->u.diadic.left; + *resultNd1 = left->u.diadic.right; + } else if (left->u.diadic.left->nodetype == ETYPCON && IRO_IsVariable(left->u.diadic.left->u.monadic)) { + if (!IsSafeTypcon(left->u.diadic.left)) + return 0; + *resultNd2 = left->u.diadic.left; + indirect = left->u.diadic.left->u.monadic; + *resultNd1 = left->u.diadic.right; + } else { + return 0; + } + } else { + return 0; + } + } else { + return 0; + } + } else if ( + ((right->flags & IROLF_LoopInvariant) || rightInvariant) && + IRO_IsVariable(left) + ) { + if (rightInvariant || ((!(obj = IRO_IsVariable(right)) || !IRO_IsRegable(obj)) && !IRO_IsConstant(right))) { + if ( + right->type == IROLinearOp2Arg && + right->nodetype == EADD && + (obj = IRO_IsVariable(right->u.diadic.left)) && + IRO_IsRegable(obj) && + IRO_IsConstant(right->u.diadic.right) + ) + return 0; + + if (leftTypcon) { + if (!IsSafeTypcon(nd->u.diadic.left)) + return 0; + *resultNd2 = nd->u.diadic.left; + } else { + *resultNd2 = left; + } + + indirect = left; + *resultNd1 = IRO_NewLinear(IROLinearOperand); + + enode = IRO_NewENode(EINTCONST); + enode->data.intval = cint64_one; + enode->rtype = nd->u.diadic.left->rtype; + (*resultNd1)->rtype = nd->u.diadic.left->rtype; + (*resultNd1)->u.node = enode; + } else { + return 0; + } + } else { + return 0; + } + } else if (nd->type == IROLinearOp2Arg && (nd->nodetype == EMUL || nd->nodetype == ESHL) && nd->rtype->size <= 4 && (IS_TYPE_INT(nd->rtype) || IS_TYPE_POINTER_ONLY(nd->rtype))) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + + if (IRO_IsConstant(right) && IRO_IsVariable(left)) { + *resultNd2 = left; + indirect = left; + *resultNd1 = right; + } else if (IRO_IsConstant(nd->u.diadic.right) && left->type == IROLinearOp1Arg && left->nodetype == ETYPCON && + IRO_IsVariable(left->u.monadic)) { + if (!IsSafeTypcon(left)) + return 0; + *resultNd2 = left; + indirect = left->u.monadic; + *resultNd1 = right; + } else { + if (nd->type == IROLinearOp2Arg && nd->nodetype == ESHL) + return 0; + + if (nd->u.diadic.right->flags & IROLF_LoopInvariant) { + if (IRO_IsVariable(left)) { + *resultNd2 = left; + indirect = left; + *resultNd1 = right; + } else if (left->type == IROLinearOp1Arg && left->nodetype == ETYPCON && IRO_IsVariable(left->u.monadic)) { + if (!IsSafeTypcon(left)) + return 0; + *resultNd2 = left; + indirect = left->u.monadic; + *resultNd1 = right; + } else { + return 0; + } + } else if (nd->u.diadic.left->flags & IROLF_LoopInvariant) { + if (IRO_IsVariable(right)) { + *resultNd2 = right; + indirect = right; + *resultNd1 = left; + } else if (right->type == IROLinearOp1Arg && right->nodetype == ETYPCON && IRO_IsVariable(right->u.monadic) && nd->type == IROLinearOp2Arg && nd->nodetype == EMUL) { + if (!IsSafeTypcon(right)) + return 0; + *resultNd2 = right; + indirect = right->u.monadic; + *resultNd1 = left; + } else { + return 0; + } + } else { + return 0; + } + } + } else if (nd->type == IROLinearOp2Arg && (nd->nodetype == EDIV || nd->nodetype == ESHR) && nd->rtype->size <= 4 && IS_TYPE_INT(nd->rtype)) { + if (IRO_IsVariable(nd->u.diadic.left) && IRO_IsConstant(nd->u.diadic.right)) { + val64 = nd->u.diadic.right->u.node->data.intval; + if (nd->type == IROLinearOp2Arg && nd->nodetype == ESHR) { + CInt64_GetULong(&val64); + if (CInt64_GetULong(&val64) > 32 || CTool_EndianReadWord32(&val64.hi)) + return 0; + val64 = CInt64_Shl(cint64_one, val64); + } + *resultNd2 = nd->u.diadic.left; + indirect = nd->u.diadic.left; + } else { + return 0; + } + } else { + return 0; + } + + if ( + nd->type == IROLinearOp2Arg && + nd->nodetype == ESHL && + ( + !IRO_IsConstant(*resultNd1) || + (SInt32) CInt64_GetULong(&(*resultNd1)->u.node->data.intval) < 0 || + (SInt32) CInt64_GetULong(&(*resultNd1)->u.node->data.intval) > 32 || + CTool_EndianReadWord32(&(*resultNd1)->u.node->data.intval.hi) + ) + ) + return 0; + + CError_ASSERT(802, indirect->u.monadic->u.node != NULL); + *resultVar = IRO_FindVar(indirect->u.monadic->u.node->data.objref, 0, 1); + if (!*resultVar || (*resultVar)->xA != 2) + return 0; + + if (copts.ANSIstrict || copts.strengthreductionstrict) { + Type *type = (*resultVar)->object->type; + if (IRO_IsUnsignedType(type) && type->size < stunsignedlong.size) + return 0; + } + + if (nd->type == IROLinearOp2Arg && (nd->nodetype == ESHR || nd->nodetype == EDIV)) { + ind = FirstInd; + while (ind && ind->var != *resultVar) + ind = ind->next; + + CError_ASSERT(845, ind != NULL); + + if (ind->addNode == NULL) { + if (ind->addConst < (val = CInt64_GetULong(&val64))) + return 0; + if ((div = ind->addConst / val) <= 0) + return 0; + + *resultNd1 = IRO_NewLinear(IROLinearOperand); + enode = IRO_NewENode(EINTCONST); + CInt64_SetULong(&enode->data.intval, div); + enode->rtype = nd->u.diadic.left->rtype; + (*resultNd1)->rtype = nd->u.diadic.left->rtype; + (*resultNd1)->u.node = enode; + } else { + return 0; + } + } + + return 1; +} + +static void IRO_RemoveExpr_Action(IROLinear *linear, Boolean isFirst) { + if (isFirst && linear->expr) + IRO_RemoveExpr(linear->expr); +} + +static void IRO_ActUnmarkRISCandidate(IROLinear *linear, Boolean isFirst) { + if (isFirst && linear->expr) + linear->flags &= ~IROLF_Ris; +} + +static IROExpr *CreateRIS(IROExpr *expr, IROLinear *nd1, IROLinear *nd2, IROLoopInd *induction, int unk) { + Object *tempObj; + Type *type; + Boolean flag23; + Object *tempObj2; + IROLinear *firstnode; + IROLinear *fourthnode; + IROLinear *fifthnode; + IROLinear *secondnode; + IROLinear *thirdnode; + IROLinear *tmp; + ENode *enode; + IROList list1; + IROList list2; + + flag23 = 0; + type = expr->linear->rtype; + tempObj = create_temp_object(type); + IRO_FindVar(tempObj, 1, 1); + IRO_InitList(&list1); + + if (IS_LINEAR_DIADIC(expr->linear, EADD)) { + firstnode = IRO_DuplicateExpr(expr->linear, &list1); + } else if (IS_LINEAR_DIADIC_2(expr->linear, EDIV, ESHR)) { + firstnode = IRO_DuplicateExpr(expr->linear, &list1); + } else { + firstnode = IRO_NewLinear(IROLinearOp2Arg); + firstnode->index = ++IRO_NumLinear; + firstnode->rtype = type; + firstnode->nodetype = EMUL; + firstnode->u.diadic.left = IRO_DuplicateExpr(nd1, &list1); + if (unk) + firstnode->u.diadic.right = IRO_DuplicateExpr(nd1, &list1); + else + firstnode->u.diadic.right = IRO_DuplicateExpr(nd2, &list1); + IRO_AddToList(firstnode, &list1); + } + + secondnode = IRO_NewLinear(IROLinearOp2Arg); + secondnode->index = ++IRO_NumLinear; + secondnode->rtype = type; + secondnode->nodetype = EASS; + secondnode->u.diadic.left = IRO_TempReference(tempObj, &list1); + secondnode->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned; + secondnode->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned; + secondnode->u.diadic.right = firstnode; + IRO_AddToList(secondnode, &list1); + IRO_Paste(list1.head, list1.tail, PredInt); + if ( + !IS_LINEAR_DIADIC_2(expr->linear, EDIV, ESHR) && + induction->addConst != 1 && + (induction->addNode || !IRO_IsConstant(nd2)) + ) { + flag23 = 1; + IRO_InitList(&list1); + thirdnode = IRO_NewLinear(IROLinearOp2Arg); + thirdnode->index = ++IRO_NumLinear; + thirdnode->rtype = nd2->rtype; + thirdnode->nodetype = EMUL; + + if (!induction->addNode) { + thirdnode->u.diadic.left = IRO_DuplicateExpr(nd2, &list1); + thirdnode->u.diadic.right = IRO_NewLinear(IROLinearOperand); + thirdnode->u.diadic.right->index = ++IRO_NumLinear; + enode = IRO_NewENode(EINTCONST); + enode->rtype = nd2->rtype; + thirdnode->u.diadic.right->rtype = nd2->rtype; + CInt64_SetLong(&enode->data.intval, induction->addConst); + thirdnode->u.diadic.right->u.node = enode; + IRO_AddToList(thirdnode->u.diadic.right, &list1); + } else { + thirdnode->u.diadic.left = IRO_DuplicateExpr(nd2, &list1); + thirdnode->u.diadic.right = IRO_DuplicateExpr(induction->addNode, &list1); + if (nd2->rtype != induction->addNode->rtype) { + tmp = IRO_NewLinear(IROLinearOp1Arg); + tmp->nodetype = ETYPCON; + tmp->index = ++IRO_NumLinear; + tmp->rtype = nd2->rtype; + tmp->u.monadic = thirdnode->u.diadic.right; + IRO_AddToList(tmp, &list1); + thirdnode->u.diadic.right = tmp; + } + } + IRO_AddToList(thirdnode, &list1); + + tempObj2 = create_temp_object(nd2->rtype); + + fourthnode = IRO_NewLinear(IROLinearOp2Arg); + fourthnode->index = ++IRO_NumLinear; + fourthnode->rtype = nd2->rtype; + fourthnode->nodetype = EASS; + fourthnode->u.diadic.left = IRO_TempReference(tempObj2, &list1); + fourthnode->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned; + fourthnode->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned; + fourthnode->u.diadic.right = thirdnode; + IRO_AddToList(fourthnode, &list1); + IRO_Paste(list1.head, list1.tail, PredInt); + } + + IRO_InitList(&list2); + fifthnode = IRO_NewLinear(IROLinearOp2Arg); + fifthnode->index = ++IRO_NumLinear; + fifthnode->rtype = type; + if (induction->nd->type == IROLinearOp2Arg) { + if (induction->nd->nodetype == EASS && IS_LINEAR_DIADIC(induction->nd->u.diadic.right, EADD)) + fifthnode->nodetype = EADDASS; + else if (induction->nd->nodetype == EASS && IS_LINEAR_DIADIC(induction->nd->u.diadic.right, ESUB)) + fifthnode->nodetype = ESUBASS; + else + fifthnode->nodetype = induction->nd->nodetype; + } else { + if (induction->nd->nodetype == EPREINC || induction->nd->nodetype == EPOSTINC) + fifthnode->nodetype = EADDASS; + else + fifthnode->nodetype = ESUBASS; + } + + fifthnode->u.diadic.left = IRO_TempReference(tempObj, &list2); + fifthnode->u.diadic.left->flags |= IROLF_Ind | IROLF_Used | IROLF_Assigned; + fifthnode->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Used | IROLF_Assigned; + if (!unk) { + if (!flag23) { + if (induction->addConst == 1 || IS_LINEAR_DIADIC_2(expr->linear, EDIV, ESHR)) { + fifthnode->u.diadic.right = IRO_DuplicateExpr(nd2, &list2); + } else { + fifthnode->u.diadic.right = IRO_NewLinear(IROLinearOperand); + fifthnode->u.diadic.right->index = ++IRO_NumLinear; + enode = IRO_NewENode(EINTCONST); + enode->rtype = nd2->rtype; + fifthnode->u.diadic.right->rtype = nd2->rtype; + CInt64_SetLong(&enode->data.intval, induction->addConst * CInt64_GetULong(&nd2->u.node->data.intval)); + fifthnode->u.diadic.right->u.node = enode; + IRO_AddToList(fifthnode->u.diadic.right, &list2); + } + } else { + fifthnode->u.diadic.right = IRO_TempReference(tempObj2, &list2); + fifthnode->u.diadic.right->flags |= IROLF_Used; + } + } + + fifthnode->index = ++IRO_NumLinear; + IRO_AddToList(fifthnode, &list2); + IRO_Paste(list2.head, list2.tail, IRO_FindStart(induction->nd)); + IRO_WalkTree(expr->linear, IRO_RemoveExpr_Action); + expr->x8 = tempObj; + expr->next = RisList; + RisList = expr; + return expr; +} + +static IRONode *CreatePreHeader(IRONode *fnode1, IRONode *fnode2) { + IROLinear *labelnode; + IRONode *newfnode; + IRONode *iter; + CLabel *oldlabel; + CLabel *newlabel; + SwitchInfo *swinfo; + SwitchCase *swcase; + + newfnode = oalloc(sizeof(IRONode)); + memset(newfnode, 0, sizeof(IRONode)); + newfnode->index = IRO_NumNodes; + IRO_NumNodes++; + + labelnode = IRO_NewLinear(IROLinearLabel); + labelnode->index = IRO_NumLinear++; + labelnode->next = NULL; + labelnode->u.label.label = IRO_NewLabel(); + labelnode->flags |= IROLF_1; + labelnode->u.label.label->stmt = (Statement *) newfnode; + newfnode->first = labelnode; + newfnode->last = labelnode; + + if (fnode2) { + fnode2->last->next = labelnode; + labelnode->next = IRO_NewLinear(IROLinearNop); + labelnode->next->next = fnode1->first; + fnode2->nextnode = newfnode; + newfnode->nextnode = fnode1; + } else { + CError_ASSERT(1254, fnode1->first->type == IROLinearLabel); + labelnode->next = IRO_NewLinear(IROLinearGoto); + labelnode->next->u.label.label = fnode1->first->u.label.label; + IRO_LastNode->last->next = labelnode; + IRO_LastNode->nextnode = newfnode; + IRO_LastNode = newfnode; + IRO_LastLinear = labelnode->next; + } + + newfnode->last = labelnode->next; + + IRO_NodeTable = oalloc(sizeof(IRONode *) * IRO_NumNodes); + memset(IRO_NodeTable, 0, sizeof(IRONode *) * IRO_NumNodes); + for (iter = IRO_FirstNode; iter; iter = iter->nextnode) + IRO_NodeTable[iter->index] = iter; + + if (fnode1->first->type == IROLinearLabel) { + oldlabel = fnode1->first->u.label.label; + newlabel = newfnode->first->u.label.label; + for (iter = IRO_FirstNode; iter; iter = iter->nextnode) { + if (!Bv_IsBitSet(iter->index, InLoop) && iter != newfnode) { + switch (iter->last->type) { + case IROLinearGoto: + if (iter->last->u.label.label == oldlabel) + iter->last->u.label.label = newlabel; + break; + case IROLinearIf: + case IROLinearIfNot: + if (iter->last->u.label.label == oldlabel) + iter->last->u.label.label = newlabel; + break; + case IROLinearSwitch: + swinfo = iter->last->u.swtch.info; + for (swcase = swinfo->cases; swcase; swcase = swcase->next) { + if (swcase->label == oldlabel) + swcase->label = newlabel; + } + if (swinfo->defaultlabel == oldlabel) + swinfo->defaultlabel = newlabel; + break; + } + } + } + } + + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + return newfnode; +} + +static IRONode *CreateNewLoopExitSuccessor(IRONode *fnode1) { + IROLinear *labelnode; + IRONode *fnode2; + IRONode *newfnode; + Boolean flag; + IRONode *iter; + CLabel *oldlabel; + CLabel *newlabel; + SwitchInfo *swinfo; + SwitchCase *swcase; + UInt16 i; + + CError_ASSERT(1355, fnode1 != NULL && LoopExitNumber == 1); + + fnode2 = NULL; + flag = 0; + + for (i = 0; i < fnode1->numpred; i++) { + iter = IRO_NodeTable[fnode1->pred[i]]; + if (Bv_IsBitSet(iter->index, InLoop_Exits)) { + CError_ASSERT(1366, fnode2 == NULL); + fnode2 = iter; + if (!flag) { + if ( + !iter->last || + !fnode1->first || + fnode1->first->type != IROLinearLabel || + ( + (iter->last->type == IROLinearIf || iter->last->type == IROLinearIfNot) && + iter->last->u.label.label != fnode1->first->u.label.label + )) + flag = 1; + } + } + } + + CError_ASSERT(1382, fnode2 != NULL); + + newfnode = oalloc(sizeof(IRONode)); + memset(newfnode, 0, sizeof(IRONode)); + newfnode->index = IRO_NumNodes; + IRO_NumNodes++; + + labelnode = IRO_NewLinear(IROLinearLabel); + labelnode->index = IRO_NumLinear++; + labelnode->next = NULL; + labelnode->u.label.label = IRO_NewLabel(); + labelnode->flags |= IROLF_1; + labelnode->u.label.label->stmt = (Statement *) newfnode; + newfnode->first = labelnode; + newfnode->last = labelnode; + + if (flag) { + fnode2->last->next = labelnode; + labelnode->next = IRO_NewLinear(IROLinearNop); + labelnode->next->next = fnode1->first; + fnode2->nextnode = newfnode; + newfnode->nextnode = fnode1; + } else { + CError_ASSERT(1422, fnode1->first->type == IROLinearLabel); + labelnode->next = IRO_NewLinear(IROLinearGoto); + labelnode->next->u.label.label = fnode1->first->u.label.label; + IRO_LastNode->last->next = labelnode; + IRO_LastNode->nextnode = newfnode; + IRO_LastNode = newfnode; + IRO_LastLinear = labelnode->next; + } + + newfnode->last = labelnode->next; + + IRO_NodeTable = oalloc(sizeof(IRONode *) * IRO_NumNodes); + memset(IRO_NodeTable, 0, sizeof(IRONode *) * IRO_NumNodes); + for (iter = IRO_FirstNode; iter; iter = iter->nextnode) + IRO_NodeTable[iter->index] = iter; + + if (fnode1->first->type == IROLinearLabel) { + oldlabel = fnode1->first->u.label.label; + newlabel = newfnode->first->u.label.label; + switch (fnode2->last->type) { + case IROLinearGoto: + if (fnode2->last->u.label.label == oldlabel) + fnode2->last->u.label.label = newlabel; + break; + case IROLinearIf: + case IROLinearIfNot: + if (fnode2->last->u.label.label == oldlabel) + fnode2->last->u.label.label = newlabel; + break; + case IROLinearSwitch: + swinfo = fnode2->last->u.swtch.info; + for (swcase = swinfo->cases; swcase; swcase = swcase->next) { + if (swcase->label == oldlabel) + swcase->label = newlabel; + } + if (swinfo->defaultlabel == oldlabel) + swinfo->defaultlabel = newlabel; + break; + } + } + + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + return newfnode; +} + +void AddPreds(IRONode *fnode) { + IRONode *pred; + int i; + + for (i = 0; i < fnode->numpred; i++) { + pred = IRO_NodeTable[fnode->pred[i]]; + if (!Bv_IsBitSet(pred->index, InLoop)) { + Bv_SetBit(pred->index, InLoop); + AddPreds(pred); + } + } +} + +static void RemoveNoopsFromExprList(void) { + IROExpr *expr; + IROExpr *prev; + + expr = IRO_FirstExpr; + prev = NULL; + while (expr) { + if (expr->linear->type == IROLinearNop) { + if (prev) + prev->next = expr->next; + else + IRO_FirstExpr = expr->next; + expr = expr->next; + } else { + prev = expr; + expr = expr->next; + } + } +} + +void IncLoopDepth(void) { + IRONode *fnode; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop)) + fnode->loopdepth++; + } +} + +void IRO_SetLoopDepth(void) { + IRONode *fnode; + IRONode *pred; + UInt16 i; + UInt16 flag; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) + fnode->loopdepth = 0; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + flag = 0; + + for (i = 0; i < fnode->numpred; i++) { + pred = IRO_NodeTable[fnode->pred[i]]; + if (Bv_IsBitSet(fnode->index, pred->dom)) { + if (!flag) { + Bv_AllocVector(&InLoop, IRO_NumNodes + 1); + Bv_Clear(InLoop); + Bv_SetBit(fnode->index, InLoop); + } + flag = 1; + Bv_SetBit(pred->index, InLoop); + if (pred != fnode) + AddPreds(pred); + } + } + + if (flag) + IncLoopDepth(); + } + + IRO_CheckForUserBreak(); +} + +static void InsertBranchAroundLoopPreheaders(void) { + IRONode *fnode; + CLabel *label; + IRONode *iter; + IROLinear *endnode; + IROLinear *labelnode; + + if (IRO_EndNode && IRO_EndNode->last && IRO_EndNode->last->type == IROLinearEnd) { + label = IRO_NewLabel(); + fnode = IRO_NewFlowGraphNode(); + IRO_LastNode->nextnode = fnode; + label->stmt = (Statement *) fnode; + + IRO_NodeTable = oalloc(sizeof(IRONode *) * IRO_NumNodes); + memset(IRO_NodeTable, 0, sizeof(IRONode *) * IRO_NumNodes); + for (iter = IRO_FirstNode; iter; iter = iter->nextnode) + IRO_NodeTable[iter->index] = iter; + + labelnode = IRO_NewLinear(IROLinearLabel); + labelnode->index = ++IRO_NumLinear; + labelnode->u.label.label = label; + labelnode->flags |= IROLF_1; + fnode->first = labelnode; + IRO_LastLinear->next = labelnode; + + endnode = IRO_NewLinear(IROLinearEnd); + memcpy(endnode, IRO_EndNode->last, sizeof(IROLinear)); + endnode->index = ++IRO_NumLinear; + endnode->next = NULL; + fnode->last = endnode; + labelnode->next = endnode; + IRO_LastLinear = endnode; + + IRO_EndNode->last->type = IROLinearGoto; + IRO_EndNode->last->u.label.label = label; + IRO_LastNode = fnode; + IRO_EndNode = fnode; + + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + } +} + +void IRO_FindLoops(void) { + IRONode *fnode; + IRONode *pred; + UInt16 i; + UInt16 flag; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + flag = 0; + + for (i = 0; i < fnode->numpred; i++) { + pred = IRO_NodeTable[fnode->pred[i]]; + if (Bv_IsBitSet(fnode->index, pred->dom)) { + if (!flag) { + Bv_AllocVector(&InLoop, IRO_NumNodes + 1); + Bv_Clear(InLoop); + Bv_SetBit(fnode->index, InLoop); + } + flag = 1; + Bv_SetBit(pred->index, InLoop); + if (pred != fnode) + AddPreds(pred); + } + } + + if (flag) { + IncLoopDepth(); + IRO_Dump("IRO_FindLoops:Found loop with header %d\n", fnode->index); + IRO_DumpBits("Loop includes: ", InLoop); + MyHandleLoop_Motion(fnode); + IRO_UpdateFlagsOnInts(); + MyHandleLoop_Vector(fnode); + RemoveNoopsFromExprList(); + IRO_UpdateFlagsOnInts(); + IRO_UpdateVars(); + } + } + + if (!IRO_FunctionHasReturn && IRO_EndNode != IRO_LastNode) + InsertBranchAroundLoopPreheaders(); +} + +static void CheckSubableSub(IROLinear *linear, Boolean isFirst) { + if (isFirst && IRO_IsSubableExpression(linear)) { + IRO_Dump("Subable Expression is %d\n", linear->index); + NoSubableSubs = 0; + } +} + +static int NoSubableSubExprs(IROLinear *nd) { + NoSubableSubs = 1; + IRO_WalkTree(nd, CheckSubableSub); + return NoSubableSubs; +} + +void ComputeLoopKills(void) { + IRONode *fnode; + IROLinear *nd; + + Bv_AllocVector(&AllKills, IRO_NumVars + 1); + Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1); + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop) && (nd = fnode->first)) { + Bv_AllocVector(&fnode->x16, IRO_NumVars + 1); + Bv_AllocVector(&fnode->x1E, IRO_NumVars + 1); + while (1) { + Bv_Clear(IRO_VarKills); + IRO_GetKills(nd); + Bv_Or(IRO_VarKills, AllKills); + if (nd == fnode->last) + break; + nd = nd->next; + } + } + } +} + +void ComputeLoopInvariance(void) { + IRONode *fnode; + IROLinear *nd; + + IRO_Depends = IRO_VarKills; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop) && (nd = fnode->first)) { + nd->flags &= ~IROLF_LoopInvariant; + while (1) { + if ((nd->flags & IROLF_Reffed) && nd->type != IROLinearNop) { + IRO_FindDepends_NoAlloc(nd); + if (!IRO_IsVolatile && !Bv_BitsInCommon(IRO_Depends, AllKills)) + nd->flags |= IROLF_LoopInvariant; + + if (IRO_CouldError) + nd->flags |= IROLF_CouldError; + else + nd->flags &= ~IROLF_CouldError; + } + + if (nd == fnode->last) + break; + nd = nd->next; + } + } + } +} + +void ComputeLoopInduction(void) { + IRONode *fnode; + IROLinear *nd; + Boolean flag; + Object *obj; + Object *obj2; + Object *obj3; + VarRecord *var; + IROLinear *tmpnd; + IROLoopInd *ind; + Boolean isUnsigned; + + Bv_AllocVector(&AllKills, IRO_NumVars + 1); + Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1); + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop) && (nd = fnode->first)) { + while (1) { + Bv_Clear(IRO_VarKills); + IRO_GetKills(nd); + Bv_Or(IRO_VarKills, AllKills); + flag = 0; + if ( + ( + nd->type == IROLinearOp2Arg && + nd->rtype->size <= 4 && + (nd->nodetype == EADDASS || nd->nodetype == ESUBASS) && + (obj = IRO_IsVariable(nd->u.diadic.left)) && + obj->type->size == nd->rtype->size && + IS_TYPE_INT(obj->type) && + ( + (IRO_IsIntConstant(nd->u.diadic.right) && CInt64_GetULong(&nd->u.diadic.right->u.node->data.intval)) + || + (nd->u.diadic.right->flags & IROLF_LoopInvariant) + ) + ) + || + ( + nd->type == IROLinearOp1Arg && + nd->rtype->size <= 4 && + (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC || nd->nodetype == EPREINC || nd->nodetype == EPREDEC) && + (obj = IRO_IsVariable(nd->u.monadic)) && + obj->type->size == nd->rtype->size && + IS_TYPE_INT(obj->type) + ) + ) + { + flag = 1; + } + else if ( + nd->type == IROLinearOp2Arg && + nd->rtype->size <= 4 && + nd->nodetype == EASS && + (obj = IRO_IsVariable(nd->u.diadic.left)) && + obj->type->size == nd->rtype->size && + IS_TYPE_INT(obj->type) && + nd->u.diadic.right->type == IROLinearOp2Arg && + (nd->u.diadic.right->nodetype == EADD || nd->u.diadic.right->nodetype == ESUB) + ) + { + if (nd->u.diadic.right->nodetype == EADD) { + obj2 = IRO_IsVariable(nd->u.diadic.right->u.diadic.left); + obj3 = IRO_IsVariable(nd->u.diadic.right->u.diadic.right); + if (obj2 == obj && obj3 != obj && (nd->u.diadic.right->u.diadic.right->flags & IROLF_LoopInvariant)) + flag = 1; + + if (obj3 == obj && obj2 != obj && (nd->u.diadic.right->u.diadic.left->flags & IROLF_LoopInvariant)) { + flag = 1; + tmpnd = nd->u.diadic.right->u.diadic.left; + nd->u.diadic.right->u.diadic.left = nd->u.diadic.right->u.diadic.right; + nd->u.diadic.right->u.diadic.right = tmpnd; + } + } else { + obj2 = IRO_IsVariable(nd->u.diadic.right->u.diadic.left); + obj3 = IRO_IsVariable(nd->u.diadic.right->u.diadic.right); + if (obj2 == obj && obj3 != obj && (nd->u.diadic.right->u.diadic.right->flags & IROLF_LoopInvariant)) + flag = 1; + } + } + + if (flag) { + if ((var = IRO_FindAssigned(nd))) { + if (var->xA == 2) + var->xA = 0; + else if (var->xA == 1) + var->xA = 2; + } + } else { + for (var = IRO_FirstVar; var; var = var->next) { + if (Bv_IsBitSet(var->index, IRO_VarKills)) + var->xA = 0; + } + } + + if (nd == fnode->last) + break; + nd = nd->next; + } + } + } + + IRO_DumpBits("Killed in loop: ", AllKills); + + for (fnode = IRO_FirstNode, FirstInd = NULL; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop) && (nd = fnode->first)) { + while (1) { + if ( + ( + nd->type == IROLinearOp2Arg && + (nd->nodetype == EADDASS || nd->nodetype == ESUBASS || nd->nodetype == EASS) + ) + || + ( + nd->type == IROLinearOp1Arg && + (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC || nd->nodetype == EPREINC || nd->nodetype == EPREDEC) + ) + ) { + if ((var = IRO_FindAssigned(nd)) && var->xA == 2 && var->object->type->size <= 4) { + ind = oalloc(sizeof(IROLoopInd)); + ind->fnode = fnode; + ind->var = var; + ind->nd = nd; + ind->next = FirstInd; + ind->addNode = NULL; + ind->addConst = 0; + ind->flags = 0; + + if (nd->type == IROLinearOp2Arg) { + isUnsigned = IRO_IsUnsignedType(nd->rtype); + if (IRO_IsIntConstant(nd->u.diadic.right)) { + CInt64 val = nd->u.diadic.right->u.node->data.intval; + if (IS_LINEAR_DIADIC(nd, EADDASS) && CInt64_Less(val, cint64_zero)) { + nd->nodetype = ESUBASS; + nd->u.diadic.right->u.node->data.intval = CInt64_Neg(val); + } + if (isUnsigned) { + CInt64_ConvertUInt32(&nd->u.diadic.right->u.node->data.intval); + ind->addConst = CInt64_GetULong(&nd->u.diadic.right->u.node->data.intval); + } else { + CInt64_ConvertInt32(&nd->u.diadic.right->u.node->data.intval); + ind->addConst = CInt64_GetULong(&nd->u.diadic.right->u.node->data.intval); + } + ind->addNode = NULL; + } else if (nd->nodetype == EADDASS || nd->nodetype == ESUBASS) { + ind->addNode = nd->u.diadic.right; + } else if (nd->nodetype == EASS) { + ind->addNode = nd->u.diadic.right->u.diadic.right; + } + } else { + if (IS_TYPE_POINTER_ONLY(nd->rtype)) + ind->addConst = TPTR_TARGET(nd->rtype)->size; + else + ind->addConst = 1; + ind->addNode = NULL; + } + + FirstInd = ind; + + if (IS_LINEAR_DIADIC_2(nd, EADDASS, ESUBASS)) { + if (nd->u.diadic.right->flags & IROLF_LoopInvariant) + IRO_Dump("Found induction variable the new way: %s\n", var->object->name->name); + else + IRO_Dump("Found induction variable the old way: %s\n", var->object->name->name); + } else if (nd->type == IROLinearOp2Arg && (nd->u.diadic.right->nodetype == EADD || nd->u.diadic.right->nodetype == ESUB)) { + IRO_Dump("Found induction variable the new way: %s\n", var->object->name->name); + } else { + IRO_Dump("Found induction variable the old way: %s\n", var->object->name->name); + } + } + } + + if (nd == fnode->last) + break; + nd = nd->next; + } + } + } +} + +static void IRO_ActUnmarkLoopInvariance(IROLinear *linear, Boolean isFirst) { + if (isFirst) + linear->flags &= ~IROLF_LoopInvariant; +} + +static void UnmarkSubexpressionsOfInvariantExpressions(void) { + IROExpr *expr; + + for (expr = IRO_FirstExpr; expr; expr = expr->next) { + if ( + Bv_IsBitSet(expr->node->index, InLoop) && + !expr->notSubable && + (!expr->couldError || expr->node->mustreach) && + (expr->linear->flags & IROLF_LoopInvariant) + ) { + IRO_WalkTree(expr->linear, IRO_ActUnmarkLoopInvariance); + expr->linear->flags |= IROLF_LoopInvariant; + } + } +} + +static void MyHandleLoop_Vector(IRONode *fnode) { + IRONode *pred; + UInt16 i; + IROExpr *expr; + IROExpr *removedExprs; + IROExpr *exprnext; + IROLoopInd *induction; + IROExpr *exprinner; + Boolean flag24; + IRONode *v2; + IRONode *node22; + int flag21; + IRONode *iter; + IROExpr *searchris; + IROLinear *reduceNd1; + VarRecord *var; + IROLinear *reduceNd2; + + IRO_FirstExpr = NULL; + LoopNode = fnode; + FindMustReach(); + + for (var = IRO_FirstVar; var; var = var->next) + var->xA = 1; + + ComputeLoopKills(); + ComputeLoopInvariance(); + ComputeLoopInduction(); + LoopNode = fnode; + ConditionalHeaderAtBottom = 0; + + v2 = NULL; + flag21 = 0; + node22 = NULL; + for (i = 0; i < LoopNode->numpred; i++) { + pred = IRO_NodeTable[LoopNode->pred[i]]; + if (!Bv_IsBitSet(pred->index, InLoop)) { + if (flag21) + node22 = NULL; + else + node22 = pred; + flag21 = 1; + if (pred->nextnode == fnode) { + CError_ASSERT(2880, v2 == NULL || pred == v2); + v2 = pred; + } + } + } + + if (!flag21) { + IRO_Dump("No predecessor outside the loop\n"); + return; + } + + if (!node22 || node22->last->type != IROLinearGoto) + node22 = CreatePreHeader(fnode, v2); + PredInt = node22->last; + + if (PredInt->type == IROLinearGoto && PredInt->u.label.label != LoopNode->first->u.label.label) { + if (!KnownBounds || !Times) { + for (iter = IRO_FirstNode; iter; iter = iter->nextnode) + iter->mustreach = 0; + } else { + PredInt->u.label.label = LoopNode->first->u.label.label; + IRO_ComputeSuccPred(); + } + } + + if (copts.loopinvariants || copts.strengthreduction) { + MoveInvarianceInAddressExpr(); + IRO_DumpAfterPhase("MoveInvarianceInAddressExpr", 0); + IRO_FindExpressions(InLoop, 1); + IRO_DumpExprs(); + } + + if (copts.loopinvariants) + UnmarkSubexpressionsOfInvariantExpressions(); + + if (!copts.optimizesize && copts.strengthreduction) { + for (expr = IRO_FirstExpr; expr; expr = expr->next) { + if ( + !(expr->x0 & 4) && + Bv_IsBitSet(expr->node->index, InLoop) && + !expr->notSubable && + (!expr->couldError || expr->node->mustreach) && + Reducable(expr->linear, &reduceNd1, &reduceNd2, &var) + ) { + IRO_WalkTree(expr->linear, IRO_ActUnmarkRISCandidate); + expr->linear->flags |= IROLF_Ris; + expr->x1A = reduceNd1; + expr->x1E = var; + expr->x22 = reduceNd2; + } + } + } + + if (!copts.optimizesize && copts.strengthreduction) { + RisList = NULL; + for (expr = IRO_FirstExpr; expr; expr = exprnext) { + exprnext = expr->next; + if (!(expr->x0 & 4) && (expr->linear->flags & IROLF_Ris)) { + reduceNd1 = expr->x1A; + var = expr->x1E; + reduceNd2 = expr->x22; + + induction = FirstInd; + while (induction && induction->var != var) + induction = induction->next; + CError_ASSERT(3529, induction != NULL); + + IRO_FindDepends(reduceNd1); + if (!Bv_BitsInCommon(IRO_Depends, AllKills)) { + IRO_Dump("Found reduction in strength: %d\n", expr->linear->index); + if (IS_LINEAR_DIADIC(expr->linear, ESHL)) { + expr->linear->nodetype = EMUL; + CInt64_SetULong(&reduceNd1->u.node->data.intval, 1 << CInt64_GetULong(&reduceNd1->u.node->data.intval)); + reduceNd1->u.node->rtype = expr->linear->rtype; + } + + searchris = RisList; + while (1) { + if (!searchris) + break; + if (IRO_ExprsSame(expr->linear, searchris->linear)) + break; + searchris = searchris->next; + } + + if (searchris) { + IRO_Dump("Using existing RIS: %d\n", searchris->linear->index); + IRO_WalkTree(expr->linear, IRO_RemoveExpr_Action); + } else { + searchris = CreateRIS(expr, reduceNd2, reduceNd1, induction, 0); + } + IRO_ReplaceReference(expr->linear, searchris->x8, expr->linear); + IRO_ClipExpr(expr); + } + } + } + } + + RisList = NULL; + + expr = IRO_FirstExpr; + removedExprs = NULL; + if (copts.loopinvariants) { + while (expr) { + exprnext = expr->next; + flag24 = 0; + + if ( + Bv_IsBitSet(expr->node->index, InLoop) && + !expr->notSubable && + (!expr->couldError || expr->node->mustreach) && + (expr->linear->flags & IROLF_LoopInvariant) && + !(expr->x0 & 4) + ) { + IRO_Dump("Found loop invariant: %d\n", expr->linear->index); + + for (exprinner = removedExprs; exprinner; exprinner = exprinner->next) { + if (IRO_ExprsSame(exprinner->linear, expr->linear)) { + IRO_ReplaceReference(expr->linear, exprinner->x8, expr->linear); + IRO_NopOut(expr->linear); + IRO_Dump("Using already removed expr: %d\n", exprinner->linear->index); + IRO_RemoveExpr(expr); + flag24 = 1; + } + } + + if (!flag24 && !expr->x8) { + IRO_GetTemp(expr); + IRO_ReplaceReference(expr->linear, expr->x8, expr->linear); + IRO_MoveExpression(expr, PredInt); + IRO_AssignToTemp(expr); + IRO_RemoveExpr(expr); + expr->next = removedExprs; + removedExprs = expr; + } + } + + expr = exprnext; + } + } +} + +static void MyHandleLoop_Motion(IRONode *fnode) { + IROLoopMemRef *memref; + IRONode *pred; + UInt16 i; + IRONode *v2; + IRONode *node21; + Object *tempobj; + int flag20; + IRONode *iter; + IROLinear *ass; + VarRecord *var; + Boolean checkflag; + IROLoop *loop; + IROList list; + IROElmList *refiter; + + IRO_FirstExpr = NULL; + LoopNode = fnode; + FindMustReach(); + + for (var = IRO_FirstVar; var; var = var->next) + var->xA = 1; + + ComputeLoopKills(); + ComputeLoopInvariance(); + ComputeLoopInduction(); + LoopNode = fnode; + ConditionalHeaderAtBottom = 0; + + v2 = NULL; + flag20 = 0; + node21 = NULL; + for (i = 0; i < LoopNode->numpred; i++) { + pred = IRO_NodeTable[LoopNode->pred[i]]; + if (!Bv_IsBitSet(pred->index, InLoop)) { + if (flag20) + node21 = NULL; + else + node21 = pred; + flag20 = 1; + if (pred->nextnode == fnode) { + CError_ASSERT(3880, v2 == NULL || pred == v2); + v2 = pred; + } + } + } + + if (!flag20) { + IRO_Dump("No predecessor outside the loop\n"); + return; + } + + if (!node21 || node21->last->type != IROLinearGoto) + node21 = CreatePreHeader(fnode, v2); + PredInt = node21->last; + + if (PredInt->type == IROLinearGoto && PredInt->u.label.label != LoopNode->first->u.label.label) { + if (!KnownBounds || !Times) { + for (iter = IRO_FirstNode; iter; iter = iter->nextnode) + iter->mustreach = 0; + } else { + PredInt->u.label.label = LoopNode->first->u.label.label; + IRO_ComputeSuccPred(); + } + } + + if (copts.loopinvariants || copts.strengthreduction) { + MoveInvarianceInAddressExpr(); + IRO_DumpAfterPhase("MoveInvarianceInAddressExpr", 0); + IRO_FindExpressions(InLoop, 0); + IRO_DumpExprs(); + } + + if (copts.loopinvariants) + UnmarkSubexpressionsOfInvariantExpressions(); + + checkflag = 1; + Bv_AllocVector(&InLoop_Exits, IRO_NumNodes + 1); + Bv_AllocVector(&InLoop_Tails, IRO_NumNodes + 1); + LoopExitNumber = 0; + LoopExitSuccessor = NULL; + LoopTailNum = 0; + LoopTail = NULL; + IRO_FindLoopTailsAndExits(fnode); + FindMustReach1(fnode); + + loop = NULL; + if (LoopTailNum == 1) { + if (fnode->last->type == IROLinearIf || fnode->last->type == IROLinearIfNot) + loop = ExtractLoopInfo(fnode); + else if (LoopTail->last->type == IROLinearIf || LoopTail->last->type == IROLinearIfNot) + loop = ExtractLoopInfo(LoopTail); + } + + if (loop && !(loop->flags & LP_IFEXPR_NON_CANONICAL) && LoopExitNumber == 1) { + IRO_LoopMemRefFirst = NULL; + IRO_LoopMemRefCurrent = NULL; + CheckAllLoopAddresses(IRO_FirstNode, InLoop, &checkflag); + CheckAllLoopAddresses(IRO_FirstNode, InLoop, &checkflag); + if (checkflag) { + for (memref = IRO_LoopMemRefFirst; memref; memref = memref->next) { + if (memref->flags & LoopMemRef_10) + memref->flags |= LoopMemRef_8; + } + + for (memref = IRO_LoopMemRefFirst; memref; memref = memref->next) { + IRO_Dump("Loop Motion Candidate:: Int= %d", memref->nd->index); + if (memref->flags & LoopMemRef_8) + IRO_Dump("<invalid>"); + if (memref->flags & LoopMemRef_1) + IRO_Dump("<load>"); + if (memref->flags & LoopMemRef_2) + IRO_Dump("<store>"); + IRO_Dump("\n"); + + if (!(memref->flags & LoopMemRef_8)) { + tempobj = create_temp_object(memref->nd->rtype); + IRO_FindVar(tempobj, 1, 1); + if (IRO_FindVar(((IROLinear *) memref->rec->objRefs->element)->u.node->data.objref, 0, 1)) { + IRO_InitList(&list); + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->rtype = memref->nd->rtype; + ass->nodetype = EASS; + ass->u.diadic.left = IRO_TempReference(tempobj, &list); + ass->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned; + ass->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned; + ass->u.diadic.right = IRO_DuplicateExpr(memref->nd, &list); + IRO_AddToList(ass, &list); + IRO_Paste(list.head, list.tail, PredInt); + } else { + CError_FATAL(4123); + } + + if (LoopExitSuccessor->numpred != 1) + LoopExitSuccessor = CreateNewLoopExitSuccessor(LoopExitSuccessor); + + IRO_InitList(&list); + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->rtype = memref->nd->rtype; + ass->nodetype = EASS; + ass->u.diadic.left = IRO_DuplicateExpr(memref->nd, &list); + ass->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned; + ass->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned; + ass->u.diadic.right = IRO_TempReference(tempobj, &list); + IRO_AddToList(ass, &list); + + if (LoopExitSuccessor->first->type == IROLinearLabel) + IRO_PasteAfter(list.head, list.tail, LoopExitSuccessor->first); + else + IRO_Paste(list.head, list.tail, LoopExitSuccessor->first); + + for (refiter = memref->list; refiter; refiter = refiter->next) { + IRO_Dump("Loop Motion Candidate Reference at Int= %d\n", ((IROLinear *) refiter->element)->index); + IRO_InitList(&list); + IRO_TempReference(tempobj, &list); + IRO_Paste(list.head, list.tail, refiter->element); + IRO_LocateFather_Cut_And_Paste(refiter->element, list.tail); + } + } + } + } + } + + IRO_DumpAfterPhase("After Motion", 0); +} + +static Boolean CheckLoopAddress(IROLinear *nd, Boolean mustreach1) { + IROLoopMemRef *memref; + IROAddrRecord *rec; + IROAddrRecord *otherrec; + IROLinear *inner; + IROElmList *list; + Boolean flag; + + inner = nd->u.monadic; + rec = IRO_InitAddrRecordPointer(inner); + if (IS_LINEAR_ENODE(inner, EOBJREF)) { + rec->numObjRefs++; + IRO_AddElmToList(inner, &rec->objRefs); + } else if (IS_LINEAR_DIADIC(inner, EADD)) { + IRO_DecomposeAddressExpression(inner, rec); + } else { + return 0; + } + + if (rec->numObjRefs != 1) + return 0; + + flag = (nd->flags & IROLF_CouldError) || !(nd->flags & IROLF_Reffed); + if (!IRO_LoopMemRefFirst) { + MakeLoopEntry(nd, rec, mustreach1, flag); + } else { + for (memref = IRO_LoopMemRefFirst; memref; memref = memref->next) { + otherrec = memref->rec; + if (((IROLinear *) rec->objRefs->element)->u.node->data.objref == ((IROLinear *) otherrec->objRefs->element)->u.node->data.objref) { + if (IRO_ExprsSame(inner, otherrec->linear)) { + list = oalloc(sizeof(IROElmList)); + list->element = nd; + list->next = NULL; + if (!memref->list) { + memref->list = list; + } else { + list->next = memref->list; + memref->list = list; + } + } else { + memref->flags |= LoopMemRef_8; + } + + if (!mustreach1 && flag) + memref->flags |= LoopMemRef_8; + if (mustreach1 || flag) + memref->flags &= ~LoopMemRef_10; + break; + } + } + + if (!memref) + MakeLoopEntry(nd, rec, mustreach1, flag); + } + + return 1; +} + +static void CheckAllLoopAddresses(IRONode *fnode, BitVector *bv, Boolean *resultFlag) { + IROLinear *nd; + Boolean flag; + + flag = *resultFlag; + while (fnode) { + if (Bv_IsBitSet(fnode->index, bv) && (nd = fnode->first)) { + while (flag) { + if (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT) + flag = CheckLoopAddress(nd, fnode->mustreach1); + else if (nd->type == IROLinearFunccall) + flag = 0; + + if (nd == fnode->last) + break; + nd = nd->next; + } + + if (!flag) + break; + } + fnode = fnode->nextnode; + } + *resultFlag = flag; +} + +static void MakeLoopEntry(IROLinear *nd, IROAddrRecord *rec, Boolean mustreach1, Boolean flag2) { + IROElmList *list; + + if (!IRO_IsRegable(((IROLinear *) rec->objRefs->element)->u.node->data.objref) && + (nd->u.monadic->flags & IROLF_LoopInvariant) && + !IRO_HasSideEffect(nd)) { + if (!IRO_LoopMemRefFirst) { + IRO_LoopMemRefCurrent = IRO_LoopMemRefFirst = oalloc(sizeof(IROLoopMemRef)); + } else { + IRO_LoopMemRefCurrent->next = oalloc(sizeof(IROLoopMemRef)); + IRO_LoopMemRefCurrent = IRO_LoopMemRefCurrent->next; + } + IRO_LoopMemRefCurrent->flags = LoopMemRef_10; + IRO_LoopMemRefCurrent->nd = nd; + IRO_LoopMemRefCurrent->rec = rec; + IRO_LoopMemRefCurrent->next = NULL; + IRO_LoopMemRefCurrent->list = NULL; + + list = oalloc(sizeof(IROElmList)); + list->element = nd; + list->next = NULL; + if (!IRO_LoopMemRefCurrent->list) { + IRO_LoopMemRefCurrent->list = list; + } else { + list->next = IRO_LoopMemRefCurrent->list; + IRO_LoopMemRefCurrent->list = list; + } + + if (((IROLinear *) rec->objRefs->element)->flags & IROLF_Assigned) { + IRO_LoopMemRefCurrent->flags |= LoopMemRef_2; + if (((IROLinear *) rec->objRefs->element)->flags & IROLF_Used) + IRO_LoopMemRefCurrent->flags |= LoopMemRef_1; + } else { + IRO_LoopMemRefCurrent->flags |= LoopMemRef_1; + } + + if (!mustreach1 && flag2) + IRO_LoopMemRefCurrent->flags |= LoopMemRef_8; + + if (mustreach1 || flag2) + IRO_LoopMemRefCurrent->flags &= ~LoopMemRef_10; + } +} + +void FindAssignmenttoInductionVar(IROLoop *loop, IRONode *fnode) { + IROLinear *nd; + UInt32 index; + + if (!loop->induction) { + loop->nd14 = NULL; + } else { + index = loop->induction->var->index; + for (nd = fnode->first; nd; nd = nd->next) { + Bv_Clear(IRO_VarKills); + IRO_GetKills(nd); + if (Bv_IsBitSet(index, IRO_VarKills)) + loop->nd14 = nd; + + if (nd == fnode->last) + break; + } + + if (loop->nd14 && loop->nd14->type != IROLinearOp2Arg) + loop->nd14 = NULL; + } +} + +static void ComputeIntWeight(IROLoop *loop, IROLinear *Int) { + loop->sizeBySomeMeasurement++; +} + +static IROLinear *IsTypconVar(IROLinear *nd) { + if (IS_LINEAR_MONADIC(nd, ETYPCON) && IRO_IsVariable(nd->u.monadic)) + return nd->u.monadic; + else + return NULL; +} + +IROLoop *ExtractLoopInfo(IRONode *fnode) { + Boolean flag30; + Boolean flag29; + Boolean flag28; + UInt32 counter27; + IROLoopInd *ind23; + Object *obj; + IROLinear *nd21; + IRONode *scanfnode; + IROLinear *left19; + IROLinear *right18; + IROLinear *tmp18; + IROLinear *scannd; + IROLinear *tmp; + VarRecord *var; + IROLoopInd *scanind; + IROLinear *left; + IROLinear *right; + UInt32 counter2; + UInt32 i; + IROLoop *loop; + + flag30 = 0; + flag29 = 0; + flag28 = 0; + counter27 = 0; + LoopNode = fnode; + + loop = oalloc(sizeof(IROLoop)); + loop->fnode = fnode; + nd21 = LoopNode->last->u.label.x4; + loop->nd18 = nd21; + loop->flags = 0; + loop->x8 = 0; + loop->nd14 = NULL; + loop->induction = NULL; + loop->index20 = -1; + loop->index24 = -1; + loop->sizeBySomeMeasurement = 0; + + if (nd21->type == IROLinearOp2Arg && IS_TYPE_INT(nd21->rtype)) { + ind23 = NULL; + left19 = nd21->u.diadic.left; + right18 = nd21->u.diadic.right; + if (IRO_IsVariable(left19) || (left19 = IsTypconVar(left19))) { + if ((var = IRO_FindVar(left19->u.monadic->u.node->data.objref, 0, 1))) { + scanind = FirstInd; + while (scanind && scanind->var != var) + scanind = scanind->next; + if (scanind) { + ind23 = scanind; + loop->flags |= LoopFlags_1; + loop->induction = scanind; + } + } + } + + if (IRO_IsVariable(right18) || (right18 = IsTypconVar(right18))) { + if ((var = IRO_FindVar(right18->u.monadic->u.node->data.objref, 0, 1))) { + scanind = FirstInd; + while (scanind && scanind->var != var) + scanind = scanind->next; + if (scanind) { + ind23 = scanind; + loop->flags &= ~LoopFlags_1; + loop->induction = scanind; + } + } + } + + if (ind23 && ind23->addConst > 0) { + if (loop->flags & LoopFlags_1) { + if ( + loop->nd18->type != IROLinearOp2Arg || + !(loop->nd18->nodetype == ELESS || loop->nd18->nodetype == EGREATER || loop->nd18->nodetype == ELESSEQU || loop->nd18->nodetype == EGREATEREQU) || + !loop->nd18->u.diadic.left || + !loop->nd18->u.diadic.left->rtype || + !IS_TYPE_INT(loop->nd18->u.diadic.left->rtype) || + !loop->nd18->u.diadic.right || + !loop->nd18->u.diadic.right->rtype || + !IS_TYPE_INT(loop->nd18->u.diadic.right->rtype) + ) { + loop->flags |= LP_IFEXPR_NON_CANONICAL; + return loop; + } + } else { + if ( + loop->nd18->type == IROLinearOp2Arg && + (loop->nd18->nodetype == EGREATER || loop->nd18->nodetype == EGREATEREQU) && + (left = loop->nd18->u.diadic.left) && + left->rtype && + IS_TYPE_INT(left->rtype) && + (right = loop->nd18->u.diadic.right) && + right->rtype && + IS_TYPE_INT(right->rtype) + ) { + loop->nd18->u.diadic.left = right; + loop->nd18->u.diadic.right = left; + if (loop->nd18->nodetype == EGREATER) + loop->nd18->nodetype = ELESS; + else if (loop->nd18->nodetype == EGREATEREQU) + loop->nd18->nodetype = ELESSEQU; + loop->flags |= LoopFlags_1; + } else if ( + loop->nd18->type == IROLinearOp2Arg && + (loop->nd18->nodetype == ELESS || loop->nd18->nodetype == ELESSEQU) && + (left = loop->nd18->u.diadic.left) && + left->rtype && + IS_TYPE_INT(left->rtype) && + (right = loop->nd18->u.diadic.right) && + right->rtype && + IS_TYPE_INT(right->rtype) + ) { + loop->nd18->u.diadic.left = right; + loop->nd18->u.diadic.right = left; + if (loop->nd18->nodetype == ELESS) + loop->nd18->nodetype = EGREATER; + else if (loop->nd18->nodetype == ELESSEQU) + loop->nd18->nodetype = EGREATEREQU; + loop->flags |= LoopFlags_1; + } else { + loop->flags |= LP_IFEXPR_NON_CANONICAL; + return loop; + } + } + } else { + loop->flags |= LP_INDUCTION_NOT_FOUND; + return loop; + } + } else if (nd21->type == IROLinearOp1Arg && IS_TYPE_INT(nd21->rtype)) { + if (nd21->nodetype == EPREINC || nd21->nodetype == EPOSTINC || nd21->nodetype == EPREDEC || nd21->nodetype == EPOSTDEC) { + if (IRO_IsVariable(nd21->u.monadic)) { + if ((var = IRO_FindVar(nd21->u.monadic->u.monadic->u.node->data.objref, 0, 1))) { + scanind = FirstInd; + while (scanind && scanind->var != var) + scanind = scanind->next; + if (scanind) { + ind23 = scanind; + loop->flags |= LoopFlags_10000; + loop->induction = scanind; + } else { + loop->flags |= LP_INDUCTION_NOT_FOUND; + return loop; + } + } else { + loop->flags |= LP_INDUCTION_NOT_FOUND; + return loop; + } + } else { + loop->flags |= LP_INDUCTION_NOT_FOUND; + return loop; + } + } else { + loop->flags |= LP_INDUCTION_NOT_FOUND; + return loop; + } + } else { + loop->flags |= LP_IFEXPR_NON_CANONICAL; + return loop; + } + + counter2 = 0; + scanind = FirstInd; + while (scanind) { + scanind = scanind->next; + counter2++; + } + + if (counter2 > 1) + loop->flags |= LP_HAS_MULTIPLE_INDUCTIONS; + + if ((scanind = loop->induction)) { + nd21 = scanind->nd; + if (nd21->type == IROLinearOp2Arg) { + if (IS_LINEAR_DIADIC_2(loop->nd18, ELESS, ELESSEQU)) { + if (nd21->nodetype == EADDASS) { + if (scanind->addConst == 1) + loop->flags |= LP_LOOP_STEP_ISADD; + if (scanind->addConst > 0) + loop->flags |= LP_LOOP_STEP_ISPOS; + } else if (nd21->nodetype == EASS && + IS_LINEAR_DIADIC(nd21->u.diadic.right, EADD) && + IRO_IsIntConstant(tmp18 = nd21->u.diadic.right->u.diadic.right) && + CTool_EndianReadWord32(&tmp18->u.node->data.intval.hi) == 0) { + if (CInt64_GetULong(&tmp18->u.node->data.intval) == 1) + loop->flags |= LP_LOOP_STEP_ISADD; + if (CInt64_GetULong(&tmp18->u.node->data.intval) > 0) + loop->flags |= LP_LOOP_STEP_ISPOS; + } + } + } else if (nd21->type == IROLinearOp1Arg) { + if (nd21->nodetype == EPREINC || nd21->nodetype == EPOSTINC) { + if (scanind->addConst == 1) + loop->flags |= LP_LOOP_STEP_ISADD; + if (scanind->addConst > 0) + loop->flags |= LP_LOOP_STEP_ISPOS; + } + if (nd21->nodetype == EPREDEC || nd21->nodetype == EPOSTDEC) { + if (scanind->addConst == 1) + loop->flags |= LoopFlags_2000; + if (scanind->addConst > 0) + loop->flags |= LP_LOOP_STEP_ISNEG; + } + } + loop->index24 = nd21->index; + loop->index20 = IRO_FindStart(nd21)->index; + } + + if (ind23) { + tmp = IRO_FindStart(fnode->last->u.diadic.right); + loop->flags |= LoopFlags_200; + if (loop->flags & LoopFlags_10000) { + for (scannd = loop->fnode->first; scannd && scannd != tmp; scannd = scannd->next) { + if (scannd->type != IROLinearLabel && scannd->type != IROLinearNop) + loop->flags &= ~LoopFlags_200; + } + } else { + for (scannd = ind23->nd->next; scannd && scannd != tmp; scannd = scannd->next){ + if (scannd->type != IROLinearLabel && scannd->type != IROLinearNop) + loop->flags &= ~LoopFlags_200; + } + for (scannd = loop->fnode->first; scannd && scannd != tmp; scannd = scannd->next){ + if ((scannd->index < loop->index20 || scannd->index > loop->index24) && scannd->type != IROLinearLabel && scannd->type != IROLinearNop) + loop->flags &= ~LoopFlags_200; + } + } + } + + for (scanfnode = IRO_FirstNode; scanfnode; scanfnode = scanfnode->nextnode) { + if (Bv_IsBitSet(scanfnode->index, InLoop) && scanfnode != fnode && (scannd = scanfnode->first)) { + while (1) { + if (scannd->type == IROLinearFunccall) + flag30 = 1; + if (scannd->type == IROLinearGoto) + flag28++; + if (flag28 >= 1) + flag29 = 1; + if (scannd->type == IROLinearIf || scannd->type == IROLinearIfNot || scannd->type == IROLinearSwitch || scannd->type == IROLinearReturn) + flag29 = 1; + + if (scannd->type == IROLinearAsm) + loop->flags |= LP_LOOP_HAS_ASM; + + if (!(scannd->flags & IROLF_Reffed) && scannd->type != IROLinearNop && scannd->type != IROLinearLabel) { + if (!IRO_IsAssignOp[scannd->nodetype]) { + loop->flags |= LoopFlags_8; + } else if (scannd->index < loop->index20 || scannd->index > loop->index24) { + counter27++; + if (IsAssignmentReductionCandidate(scannd) && counter27 == 1) + loop->flags |= LoopFlags_40000; + if (counter27 > 1) + loop->flags &= ~LoopFlags_40000; + } + } + + if (scannd->index < loop->index20 || scannd->index > loop->index24) { + if (IS_LINEAR_ENODE(scannd, EOBJREF)) { + obj = scannd->u.node->data.objref; + if ((scannd->flags & IROLF_Ind) && obj && obj == loop->induction->var->object) { + if (!(scannd->flags & IROLF_Assigned) && (scannd->flags & IROLF_Used)) { + IRO_Dump("Induction Used in loop\n"); + loop->flags |= LoopFlags_800; + } + } + } + + if (IS_LINEAR_DIADIC(scannd, ESHR) && + (obj = IRO_IsVariable(scannd->u.diadic.left)) && + IRO_IsIntConstant(scannd->u.diadic.right)) { + for (scanind = FirstInd; scanind; scanind = scanind->next) { + if (scanind->var->object == obj) { + IRO_Dump("Induction has DIV: %s\n", obj->name->name); + scanind->flags |= LoopInd_HasDiv; + } + } + } + + if (IS_LINEAR_DIADIC(scannd, EAND) && + (obj = IRO_IsVariable(scannd->u.diadic.left)) && + IRO_IsIntConstant(scannd->u.diadic.right)) { + for (scanind = FirstInd; scanind && obj; scanind = scanind->next) { + if (scanind->var->object == obj) { + IRO_Dump("Induction has MOD: %s\n", obj->name->name); + scanind->flags |= LoopInd_HasMod; + } + } + } + } + + ComputeIntWeight(loop, scannd); + if (scannd == scanfnode->last) + break; + scannd = scannd->next; + } + } + + if (flag30) + loop->flags |= LP_LOOP_HAS_CALLS; + if (flag29) + loop->flags |= LP_LOOP_HAS_CNTRLFLOW; + + for (i = 0; i < scanfnode->numsucc && scanfnode != fnode; i++) { + if (Bv_IsBitSet(scanfnode->index, InLoop) && !Bv_IsBitSet(scanfnode->succ[i], InLoop)) { + IRO_Dump("Node %d has an out of loop successor %d\n", scanfnode->index, scanfnode->succ[i]); + IRO_DumpBits("Loop includes: ", InLoop); + IRO_Dump("loop has multiple exits\n"); + loop->flags |= LoopFlags_1000; + } + } + } + + return loop; +} + +CLabel *BuildLabel(IROList *list) { + IROLinear *nd; + + nd = IRO_NewLinear(IROLinearLabel); + nd->index = IRO_NumLinear++; + nd->u.label.label = IRO_NewLabel(); + nd->flags |= IROLF_1; + IRO_AddToList(nd, list); + return nd->u.label.label; +} + +static void MoveInvarianceInAddressExpr(void) { + IRONode *fnode; + IROLinear *nd; + IROLinear *start; + IROList list; + + IRO_FirstExpr = IRO_LastExpr = NULL; + IRO_NumExprs = 0; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (Bv_IsBitSet(fnode->index, InLoop)) { + for (nd = fnode->first; nd; nd = nd->next) { + if (nd->type == IROLinearOp1Arg && + (nd->nodetype == EINDIRECT || nd->nodetype == EINDIRECT) && + IS_LINEAR_DIADIC(nd->u.monadic, EADD)) { + RearrangeInvarianceInAddressExpr(nd->u.monadic, &list); + start = IRO_FindStart(nd->u.monadic); + IRO_LocateFather_Cut_And_Paste(nd->u.monadic, list.tail); + IRO_Paste(list.head, list.tail, start); + } + + if (nd == fnode->last) + break; + } + } + } + + IRO_UpdateFlagsOnInts(); +} + +static void AddAddendLinear(IROLinear *nd) { + IROElmList *list; + + if (IS_LINEAR_DIADIC(nd, EADD)) { + AddAddendLinear(nd->u.diadic.left); + AddAddendLinear(nd->u.diadic.right); + } else { + list = oalloc(sizeof(IROElmList)); + list->element = nd; + list->next = NULL; + if (FirstAddendLinear) + LastAddendLinear->next = list; + else + FirstAddendLinear = list; + LastAddendLinear = list; + } +} + +static IROLinear *RearrangeInvarianceInAddressExpr(IROLinear *nd, IROList *list) { + IROLinear *result; + IROElmList *scanlist; + IROElmList *elist; + IROLinear *scannd; + + IRO_InitList(list); + FirstAddendLinear = LastAddendLinear = NULL; + AddAddendLinear(nd->u.diadic.left); + AddAddendLinear(nd->u.diadic.right); + + elist = NULL; + result = NULL; + for (scanlist = FirstAddendLinear; scanlist; scanlist = scanlist->next) { + scannd = scanlist->element; + if (!IRO_IsIntConstant(scannd) && (scannd->flags & IROLF_LoopInvariant)) { + if (result) { + IROLinear *tmp = IRO_NewLinear(IROLinearOp2Arg); + tmp->index = ++IRO_NumLinear; + tmp->nodetype = EADD; + tmp->u.diadic.left = result; + tmp->u.diadic.right = IRO_DuplicateExpr(scannd, list); + IRO_AddToList(tmp, list); + tmp->flags |= IROLF_LoopInvariant; + tmp->flags |= IROLF_Reffed; + tmp->rtype = result->rtype; + result = tmp; + } else { + result = IRO_DuplicateExpr(scannd, list); + } + + if (elist) + elist->next = scanlist->next; + else + FirstAddendLinear = scanlist->next; + } else { + elist = scanlist; + } + } + + for (scanlist = FirstAddendLinear, elist = NULL; scanlist; scanlist = scanlist->next) { + scannd = scanlist->element; + if (!IRO_IsIntConstant(scannd)) { + if (result) { + IROLinear *tmp = IRO_NewLinear(IROLinearOp2Arg); + tmp->index = ++IRO_NumLinear; + tmp->nodetype = EADD; + tmp->u.diadic.left = result; + tmp->u.diadic.right = IRO_DuplicateExpr(scannd, list); + IRO_AddToList(tmp, list); + tmp->flags |= IROLF_Reffed; + tmp->rtype = result->rtype; + result = tmp; + } else { + result = IRO_DuplicateExpr(scannd, list); + } + + if (elist) + elist->next = scanlist->next; + else + FirstAddendLinear = scanlist->next; + } else { + elist = scanlist; + } + } + + for (scanlist = FirstAddendLinear; scanlist; scanlist = scanlist->next) { + scannd = scanlist->element; + if (result) { + IROLinear *tmp = IRO_NewLinear(IROLinearOp2Arg); + tmp->index = ++IRO_NumLinear; + tmp->nodetype = EADD; + tmp->u.diadic.left = result; + tmp->u.diadic.right = scannd; + tmp->u.diadic.right = IRO_DuplicateExpr(scannd, list); + IRO_AddToList(tmp, list); + tmp->flags |= IROLF_Reffed; + tmp->rtype = result->rtype; + result = tmp; + } else { + result = IRO_DuplicateExpr(scannd, list); + } + } + + return result; +} + +static IROLinear *FindAddendForReductionPattern(IROLinear *a, IROLinear *b, Boolean *resultFlag) { + IROLinear *left; + IROLinear *right; + IROLinear *node28; + Boolean subflag; + + left = b->u.diadic.left; + right = b->u.diadic.right; + if (b->nodetype == EADD || b->nodetype == ESUB) { + node28 = left; + while (IS_LINEAR_MONADIC(node28, ETYPCON)) + node28 = node28->u.monadic; + + if (IS_LINEAR_MONADIC(node28, EINDIRECT) && (node28->u.monadic->flags & IROLF_LoopInvariant) && IRO_ExprsSame(a, node28)) { + *resultFlag = 1; + return left; + } + + if (IS_LINEAR_DIADIC_2(node28, EADD, ESUB)) { + if ((node28 = FindAddendForReductionPattern(a, node28, &subflag))) { + *resultFlag = 1; + return node28; + } + } + } + + *resultFlag = 0; + if (b->nodetype == EADD) { + node28 = right; + while (IS_LINEAR_MONADIC(node28, ETYPCON)) + node28 = node28->u.monadic; + + if (IS_LINEAR_MONADIC(node28, EINDIRECT) && (node28->u.monadic->flags & IROLF_LoopInvariant) && IRO_ExprsSame(a, node28)) { + return right; + } + + if (IS_LINEAR_DIADIC_2(node28, EADD, ESUB)) { + if ((node28 = FindAddendForReductionPattern(a, node28, &subflag))) { + return node28; + } + } + } + + return NULL; +} + +static void ReorderOperandsForReductionPattern(IROLinear *a, IROLinear *b) { + IROLinear *left; + IROLinear *right; + IROLinear *addend; + IROLinear *tmp; + Boolean flag; + + left = b->u.diadic.left; + right = b->u.diadic.right; + + if (b->nodetype == EADD && (addend = FindAddendForReductionPattern(a, b, &flag)) && addend != left) { + if (flag && IS_LINEAR_DIADIC_2(left, EADD, ESUB) && addend->rtype == right->rtype) { + tmp = left; + b->u.diadic.left = right; + left = right; + b->u.diadic.right = tmp; + right = tmp; + flag = 0; + } + + if (!flag && IS_LINEAR_DIADIC_2(right, EADD, ESUB) && addend->rtype == left->rtype) { + if (IRO_LocateFather_Cut_And_Paste_Without_Nopping(addend, left)) + b->u.diadic.left = addend; + } + } +} + +static UInt32 IsAssignmentReductionCandidate(IROLinear *nd) { + IROLinear *left; + IROLinear *right; + IROLinear *tmp; + + if (nd->type == IROLinearOp2Arg) { + if (nd->nodetype == EASS) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + if (IS_LINEAR_MONADIC(left, EINDIRECT) && (left->u.monadic->flags & IROLF_LoopInvariant)) { + if (IS_LINEAR_MONADIC(right, ETYPCON) && + right->rtype->type == right->u.monadic->rtype->type && + IS_TYPE_INT(right->rtype) && + right->rtype->size < right->u.monadic->rtype->size) + right = right->u.monadic; + + if (IS_LINEAR_DIADIC_2(right, EADD, ESUB)) { + ReorderOperandsForReductionPattern(left, right); + tmp = right->u.diadic.left; + if (IS_LINEAR_MONADIC(tmp, ETYPCON)) + tmp = tmp->u.monadic; + if (IS_LINEAR_MONADIC(tmp, EINDIRECT) && + (tmp->u.monadic->flags & IROLF_LoopInvariant) && + IRO_ExprsSame(left, tmp) && + right->u.diadic.right->type == IROLinearOp2Arg) { + if (right->u.diadic.right->nodetype == EADD) + return 1; + if (right->u.diadic.right->nodetype == ESUB) + return 1; + if (right->u.diadic.right->nodetype == EMUL) + return 1; + if (right->u.diadic.right->nodetype == EDIV) + return 1; + } + } + } + } else if (nd->nodetype == EADDASS || nd->nodetype == ESUBASS) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + + if (IS_LINEAR_MONADIC(right, ETYPCON) && + right->rtype->type == right->u.monadic->rtype->type && + IS_TYPE_INT(right->rtype) && + right->rtype->size < right->u.monadic->rtype->size) + right = right->u.monadic; + + if (IS_LINEAR_MONADIC(left, EINDIRECT) && + (left->u.monadic->flags & IROLF_LoopInvariant) && + right->type == IROLinearOp2Arg) { + if (right->nodetype == EADD) + return 1; + if (right->nodetype == ESUB) + return 1; + if (right->nodetype == EMUL) + return 1; + if (right->nodetype == EDIV) + return 1; + } + } + } + + return 0; +} + diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroLoop.h b/compiler_and_linker/FrontEnd/Optimizer/IroLoop.h new file mode 100644 index 0000000..2d968ad --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroLoop.h @@ -0,0 +1,111 @@ +#ifndef COMPILER_IROLOOP_H +#define COMPILER_IROLOOP_H + +#include "IrOptimizer.h" +#include "BitVector.h" + +typedef enum IROLoopIndFlags { + LoopInd_HasMod = 1, + LoopInd_HasDiv = 2, + LoopInd_4 = 4, + LoopInd_8 = 8 +} IROLoopIndFlags; + +typedef enum IROLoopFlags { + LoopFlags_1 = 1, // LP_INDUCTION_AT_LEFT + LP_LOOP_HAS_CALLS = 2, + LP_LOOP_HAS_CNTRLFLOW = 4, + LoopFlags_8 = 8, // LP_HAS_NONASSIGN + LP_INDUCTION_NOT_FOUND = 0x10, + LP_IFEXPR_NON_CANONICAL = 0x20, + LP_HAS_MULTIPLE_INDUCTIONS = 0x40, + LP_LOOP_HDR_HAS_SIDEEFFECTS = 0x80, + LP_LOOP_STEP_ISADD = 0x100, + LoopFlags_200 = 0x200, // LP_HEADER_FOLLOWS_UPDATE? + LP_LOOP_STEP_ISPOS = 0x400, + LoopFlags_800 = 0x800, // LP_IND_USED_IN_LOOP + LoopFlags_1000 = 0x1000, // LP_HAS_MULTIPLE_EXITS + LoopFlags_2000 = 0x2000, // inverse of LP_LOOP_STEP_ISADD? + LP_LOOP_STEP_ISNEG = 0x4000, + LP_LOOP_HAS_ASM = 0x8000, + LoopFlags_10000 = 0x10000, // LP_WHILE_LOOP + LoopFlags_20000 = 0x20000, // maybe LP_RECURSIVE_LOOP? + LoopFlags_40000 = 0x40000 // LP_IS_REDUCTION_CAND +} IROLoopFlags; + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct IROLoopInd { + IROLoopIndFlags flags; + VarRecord *var; + IRONode *fnode; + IROLinear *nd; + SInt32 addConst; + IROLinear *addNode; + struct IROLoopInd *next; +} IROLoopInd; + +struct IROLoop { + SInt32 flags; + IRONode *fnode; + int x8; + IRONode *xC; + IRONode *x10; + IROLinear *nd14; // assignment expression that sets the initial value of induction + IROLinear *nd18; // ifexpr? + IROLoopInd *induction; + int index20; + int index24; + CInt64 x28; + CInt64 x30; + int sizeBySomeMeasurement; +}; + +typedef enum IROLoopMemRefFlags { + LoopMemRef_1 = 1, + LoopMemRef_2 = 2, + LoopMemRef_4 = 4, + LoopMemRef_8 = 8, + LoopMemRef_10 = 0x10 +} IROLoopMemRefFlags; + +typedef struct IROLoopMemRef { + IROLoopMemRefFlags flags; + IROLinear *nd; + IROElmList *list; + IROAddrRecord *rec; + struct IROLoopMemRef *next; +} IROLoopMemRef; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +extern IRONode *LoopNode; +extern Boolean ConditionalHeaderAtBottom; +extern IROLoopInd *FirstInd; +extern BitVector *InLoop; +extern IROList IRO_InitLList; +extern BitVector *InLoop_Exits; +extern BitVector *InLoop_Tails; +extern UInt32 LoopExitNumber; +extern UInt32 LoopTailNum; +extern IRONode *LoopExitSuccessor; +extern IRONode *LoopTail; +extern IROLoopMemRef *IRO_LoopMemRefFirst; +extern IROLoopMemRef *IRO_LoopMemRefCurrent; + +extern void FindMustReach(void); +extern void FindMustReach1(IRONode *checkfnode); +extern void AddPreds(IRONode *fnode); +extern void IncLoopDepth(void); +extern void IRO_SetLoopDepth(void); +extern void IRO_FindLoops(void); +extern void ComputeLoopKills(void); +extern void ComputeLoopInvariance(void); +extern void ComputeLoopInduction(void); +extern void FindAssignmenttoInductionVar(IROLoop *loop, IRONode *fnode); +extern IROLoop *ExtractLoopInfo(IRONode *fnode); +extern CLabel *BuildLabel(IROList *list); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c b/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c new file mode 100644 index 0000000..1f15cad --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c @@ -0,0 +1,564 @@ +#include "IroMalloc.h" +#include "compiler/CompilerTools.h" + +#define FLAGMASK 0xF + +typedef struct Block { + struct Block *prev; + struct Block *next; + void *x8; + void *xC; + size_t remain; + size_t x14; +} Block; + +typedef struct SubBlockBase { + size_t x0; + Block *block; +} SubBlockBase; + +typedef struct SubBlock { + size_t x0; + Block *block; + struct SubBlock *x8; + struct SubBlock *xC; +} SubBlock; + +typedef struct SubBlockTail { + size_t x0copy; +} SubBlockTail; + +typedef struct BlockTail { + size_t x14copy; + SubBlock *unk; +} BlockTail; + +typedef struct FixStart { + struct FixBlock *a; + struct FixSubBlock *b; + long count; +} FixStart; + +typedef struct FixBlock { + struct FixBlock *prev; + struct FixBlock *next; + size_t entrysize; +} FixBlock; + +typedef struct FixSubBlockBase { + FixBlock *fixblock; +} FixSubBlockBase; + +typedef struct FixSubBlock { + FixBlock *fixblock; + struct FixSubBlock *next; +} FixSubBlock; + +static const size_t fix_pool_sizes[] = {0xC, 0x1C, 0x2C, 0x4C}; +static Block *start_; +static FixStart fix_start[4]; +static int initialized; + +// forward decls +static void Block_link(Block *block, SubBlock *subblock); +static void Block_unlink(Block *block, SubBlock *subblock); +static void SubBlock_construct(SubBlock *subblock, size_t size, Block *block, int flag1, int flag2); +static SubBlock *SubBlock_split(SubBlock *subblock, size_t pos); +static SubBlock *SubBlock_merge_prev(SubBlock *subblock, SubBlock **sbptr); +static void SubBlock_merge_next(SubBlock *subblock, SubBlock **sbptr); + +#define BLOCK_TAIL(block) ((BlockTail *) ((long) (block) + ((block)->x14 & ~FLAGMASK) - sizeof(BlockTail))) + +#define BUF_LOCATOR(buf) (*((size_t *) ((long) (buf) - sizeof(size_t)))) +#define SBB_BLOCK(sbb) ((Block *) ((long) ((sbb)->block) & ~1)) + +#define BUF_IS_VAR(buf) (BUF_LOCATOR(buf) & 1) +#define VARBUF_SBB(buf) ((SubBlockBase *) ((long) (buf) - sizeof(SubBlockBase))) +#define VARBUF_SB(buf) ((SubBlock *) ((long) (buf) - sizeof(SubBlockBase))) +#define VARBUF_BLOCKSIZE(buf) (VARBUF_SBB(buf)->x0 & ~FLAGMASK) +#define VARBUF_SIZE(buf) (((VARBUF_SBB(buf)->x0 & ~FLAGMASK) - sizeof(SubBlockBase))) +#define VARBUF_BLOCK(buf) SBB_BLOCK(VARBUF_SBB(buf)) +#define FIXBUF_SIZE(buf) (((FixBlock *) BUF_LOCATOR(buf))->entrysize) + +#define BUF_SIZE(buf) BUF_IS_VAR(buf) ? VARBUF_SIZE(buf) : FIXBUF_SIZE(buf) + +static void Block_construct(Block *block, size_t size) { + SubBlock *subblock; + + block->x14 = size | 3; + ((BlockTail *) ((long) block + size - sizeof(BlockTail)))->x14copy = block->x14; + + subblock = (SubBlock *) (block + 1); + SubBlock_construct(subblock, size - sizeof(Block) - sizeof(BlockTail), block, 0, 0); + + block->remain = size - sizeof(Block) - sizeof(BlockTail); + BLOCK_TAIL(block)->unk = NULL; + + Block_link(block, subblock); +} + +static SubBlock *Block_subBlock(Block *block, size_t size) { + SubBlock *subblock; + size_t check; + size_t best; + + if (!BLOCK_TAIL(block)->unk) + return NULL; + + subblock = BLOCK_TAIL(block)->unk; + best = subblock->x0 & ~FLAGMASK; + check = subblock->x0 & ~FLAGMASK; + while (check < size) { + subblock = subblock->xC; + check = subblock->x0 & ~FLAGMASK; + if (best < check) + best = check; + if (subblock == BLOCK_TAIL(block)->unk) { + block->remain = best; + return NULL; + } + } + + if ((check - size) >= 0x60) + SubBlock_split(subblock, size); + + BLOCK_TAIL(block)->unk = subblock->xC; + Block_unlink(block, subblock); + return subblock; +} + +static void Block_link(Block *block, SubBlock *subblock) { + size_t size; + SubBlock **sbptr; + + size = subblock->x0 & ~FLAGMASK; + subblock->x0 &= ~2; + ((SubBlock *) ((long) subblock + size))->x0 &= ~4; + ((SubBlockTail *) ((long) subblock + size - sizeof(SubBlockTail)))->x0copy = size; + + sbptr = &BLOCK_TAIL(block)->unk; + if (*sbptr) { + subblock->x8 = (*sbptr)->x8; + subblock->x8->xC = subblock; + subblock->xC = *sbptr; + (*sbptr)->x8 = subblock; + *sbptr = subblock; + *sbptr = SubBlock_merge_prev(*sbptr, sbptr); + SubBlock_merge_next(*sbptr, sbptr); + } else { + *sbptr = subblock; + subblock->x8 = subblock; + subblock->xC = subblock; + } + + if (block->remain < ((*sbptr)->x0 & ~FLAGMASK)) + block->remain = (*sbptr)->x0 & ~FLAGMASK; +} + +static void Block_unlink(Block *block, SubBlock *subblock) { + size_t size; + SubBlock **sbptr; + + size = subblock->x0 & ~FLAGMASK; + subblock->x0 |= 2; + ((SubBlock *) ((long) subblock + size))->x0 |= 4; + + sbptr = &BLOCK_TAIL(block)->unk; + if (*sbptr == subblock) + *sbptr = subblock->xC; + + if (*sbptr == subblock) { + *sbptr = NULL; + block->remain = 0; + } else { + subblock->xC->x8 = subblock->x8; + subblock->x8->xC = subblock->xC; + } +} + +static void SubBlock_construct(SubBlock *subblock, size_t size, Block *block, int flag1, int flag2) { + subblock->block = (Block *) ((long) block | 1); + subblock->x0 = size; + if (flag1) + subblock->x0 |= 4; + if (flag2) { + subblock->x0 |= 2; + ((SubBlock *) (((long) subblock) + size))->x0 |= 4; + } else { + ((SubBlockTail *) (((long) subblock) + size - sizeof(SubBlockTail)))->x0copy = size; + } +} + +static SubBlock *SubBlock_split(SubBlock *subblock, size_t pos) { + size_t oldsize; + int flag; + SubBlock *splitright; + Block *block; + + oldsize = subblock->x0 & ~FLAGMASK; + flag = !(subblock->x0 & 2); + splitright = (SubBlock *) ((long) subblock + pos); + block = (Block *) ((long) subblock->block & ~1); + SubBlock_construct(subblock, pos, block, subblock->x0 & 4, !flag); + SubBlock_construct(splitright, oldsize - pos, block, !flag, !flag); + if (flag) { + splitright->xC = subblock->xC; + splitright->xC->x8 = splitright; + splitright->x8 = subblock; + subblock->xC = splitright; + } + + return splitright; +} + +static SubBlock *SubBlock_merge_prev(SubBlock *subblock, SubBlock **sbptr) { + size_t prevsize; + SubBlock *prevblock; + + if (!(subblock->x0 & 4)) { + prevsize = ((SubBlockTail *) ((long) subblock - sizeof(SubBlockTail)))->x0copy; + if (prevsize & 2) + return subblock; + + prevblock = (SubBlock *) ((long) subblock - prevsize); + prevblock->x0 = prevblock->x0 & FLAGMASK; + prevblock->x0 |= (prevsize + (subblock->x0 & ~FLAGMASK)) & ~FLAGMASK; + if (!(prevblock->x0 & 2)) + ((SubBlockTail *) ((long) prevblock + prevsize + (subblock->x0 & ~FLAGMASK) - sizeof(SubBlockTail)))->x0copy = prevsize + (subblock->x0 & ~FLAGMASK); + + if (*sbptr == subblock) + *sbptr = (*sbptr)->xC; + + subblock->xC->x8 = subblock->x8; + subblock->xC->x8->xC = subblock->xC; + return prevblock; + } + + return subblock; +} + +static void SubBlock_merge_next(SubBlock *subblock, SubBlock **sbptr) { + SubBlock *nextblock; + size_t nextsize; + + nextblock = (SubBlock *) ((long) subblock + (subblock->x0 & ~FLAGMASK)); + if (!(nextblock->x0 & 2)) { + nextsize = (subblock->x0 & ~FLAGMASK) + (nextblock->x0 & ~FLAGMASK); + subblock->x0 = subblock->x0 & FLAGMASK; + subblock->x0 |= nextsize & ~FLAGMASK; + + if (!(subblock->x0 & 2)) + ((SubBlockTail *) ((long) subblock + nextsize - sizeof(SubBlockTail)))->x0copy = nextsize; + + if (!(subblock->x0 & 2)) + ((SubBlock *) ((long) subblock + nextsize))->x0 &= ~4; + else + ((SubBlock *) ((long) subblock + nextsize))->x0 |= 4; + + if (*sbptr == nextblock) + *sbptr = (*sbptr)->xC; + if (*sbptr == nextblock) + *sbptr = NULL; + + nextblock->xC->x8 = nextblock->x8; + nextblock->x8->xC = nextblock->xC; + } +} + +static void link_block(Block *block) { + if (start_) { + block->prev = start_->prev; + block->prev->next = block; + block->next = start_; + + start_->prev = block; + start_ = block; + } else { + start_ = block; + block->prev = block; + block->next = block; + } +} + +static Block *unlink_block(Block *block) { + Block *newblock; + + newblock = block->next; + if (newblock == block) + newblock = NULL; + + if (start_ == block) + start_ = newblock; + + if (newblock) { + newblock->prev = block->prev; + newblock->prev->next = newblock; + } + + block->prev = block->next = NULL; + return newblock; +} + +static Block *link_new_block(size_t size) { + Block *block; + + size = (size + 0x1000 + sizeof(Block) + sizeof(BlockTail) - 1) & ~0xFFF; + if (size < 0x10000) + size = 0x10000; + + if (!(block = galloc(size))) + return NULL; + + Block_construct(block, size); + link_block(block); + return block; +} + +static void *allocate_from_var_pools(size_t size) { + Block *block; + SubBlock *subblock; + + size = (size + sizeof(Block) - 1) & ~0xF; + if (size < 0x60) + size = 0x60; + + block = start_ ? start_ : link_new_block(size); + if (!block) + return NULL; + + do { + if (size <= block->remain) { + if ((subblock = Block_subBlock(block, size))) { + start_ = block; + goto allocated; + } + } + } while ((block = block->next) != start_); + + block = link_new_block(size); + if (!block) + return NULL; + subblock = Block_subBlock(block, size); +allocated: + return (SubBlockBase *) subblock + 1; +} + +static void deallocate_from_var_pools(void *buf) { + Block *block; + SubBlock *subblock; + int flag; + + subblock = (SubBlock *) ((long) buf - sizeof(SubBlockBase)); + block = (Block *) ((long) subblock->block & ~1); + Block_link(block, subblock); + + flag = 0; + subblock = (SubBlock *) (block + 1); + if (!(subblock->x0 & 2)) { + if ((subblock->x0 & ~FLAGMASK) == ((block->x14 & ~FLAGMASK) - sizeof(Block) - sizeof(BlockTail))) + flag = 1; + } + + if (flag) + unlink_block(block); +} + +static void FixBlock_construct(FixBlock *fixblock, FixBlock *prev, FixBlock *next, int poolIndex, void *buffer, size_t buffersize) { + size_t entrysize; + size_t entrycount; + size_t i; + FixSubBlock *fsb; + FixSubBlock *fsbnext; + + fixblock->prev = prev; + fixblock->next = next; + fixblock->entrysize = fix_pool_sizes[poolIndex]; + + entrysize = fix_pool_sizes[poolIndex] + sizeof(void *); + entrycount = (buffersize / entrysize); + fsb = buffer; + for (i = 0; i < (entrycount - 1); i++) { + fsbnext = (FixSubBlock *) ((long) fsb + entrysize); + fsb->fixblock = fixblock; + fsb->next = fsbnext; + fsb = fsbnext; + } + + fsb->fixblock = fixblock; + fsb->next = fix_start[poolIndex].b; + fix_start[poolIndex].b = buffer; +} + +static void *allocate_from_fixed_pools(size_t size) { + int poolIndex; + FixSubBlock *fsb; + + poolIndex = 0; + while (size > fix_pool_sizes[poolIndex]) + poolIndex++; + + if (!fix_start[poolIndex].b) { + void *buf; + size_t bufsize; + + buf = allocate_from_var_pools(4000); + if (!buf) + return NULL; + + bufsize = !BUF_IS_VAR(buf) ? FIXBUF_SIZE(buf) : VARBUF_SIZE(buf); + FixBlock_construct( + buf, NULL, fix_start[poolIndex].a, poolIndex, + ((FixBlock *) buf) + 1, + bufsize - sizeof(FixBlock) + ); + fix_start[poolIndex].a = buf; + } + + fsb = fix_start[poolIndex].b; + fix_start[poolIndex].b = fsb->next; + fix_start[poolIndex].count++; + return ((FixSubBlockBase *) fsb) + 1; +} + +static void deallocate_from_fixed_pools(void *buf, size_t size) { + int poolIndex; + FixBlock *fixblock; + FixBlock *nextfb; + FixSubBlock *fsb; + + poolIndex = 0; + while (size > fix_pool_sizes[poolIndex]) + poolIndex++; + + fsb = (FixSubBlock *) ((long) buf - sizeof(FixSubBlockBase)); + fsb->next = fix_start[poolIndex].b; + fix_start[poolIndex].b = fsb; + if (--fix_start[poolIndex].count == 0) { + fixblock = fix_start[poolIndex].a; + while (fixblock) { + nextfb = fixblock->next; + deallocate_from_var_pools(fixblock); + fixblock = nextfb; + } + fix_start[poolIndex].a = NULL; + fix_start[poolIndex].b = NULL; + } +} + +size_t IRO_msize(void *buf) { + return BUF_SIZE(buf); +} + +void *IRO_malloc(size_t size) { + if (!size) + return NULL; + + if (size <= 0x4C) + return allocate_from_fixed_pools(size); + else + return allocate_from_var_pools(size); +} + +void IRO_free(void *buf) { + if (buf) { + size_t size = !BUF_IS_VAR(buf) ? FIXBUF_SIZE(buf) : VARBUF_SIZE(buf); + + if (size <= 0x4C) + deallocate_from_fixed_pools(buf, size); + else + deallocate_from_var_pools(buf); + } +} + +void *IRO_realloc(void *buf, size_t newsize) { + size_t oldsize; + size_t newblocksize; + void *newbuf; + + if (!buf) + return IRO_malloc(newsize); + + if (!newsize) { + IRO_free(buf); + return NULL; + } + + oldsize = !BUF_IS_VAR(buf) ? FIXBUF_SIZE(buf) : VARBUF_SIZE(buf); + if (newsize > oldsize) { + if (BUF_IS_VAR(buf)) { + newblocksize = (newsize + sizeof(Block) - 1) & ~FLAGMASK; + if (newblocksize < 0x60) + newblocksize = 0x60; + SubBlock_merge_next(VARBUF_SB(buf), &BLOCK_TAIL(VARBUF_BLOCK(buf))->unk); + if (VARBUF_BLOCKSIZE(buf) >= newblocksize) { + if ((VARBUF_BLOCKSIZE(buf) - newblocksize) >= 0x60) { + Block_link(VARBUF_BLOCK(buf), SubBlock_split(VARBUF_SB(buf), newblocksize)); + } + return buf; + } + } + + newbuf = IRO_malloc(newsize); + if (!newbuf) + return NULL; + + memcpy(newbuf, buf, oldsize); + IRO_free(buf); + return newbuf; + } + + if (BUF_IS_VAR(buf)) { + newsize = (newsize + sizeof(Block) - 1) & ~FLAGMASK; + if (newsize < 0x60) + newsize = 0x60; + if ((VARBUF_BLOCKSIZE(buf) - newsize) >= 0x60) { + Block_link(VARBUF_BLOCK(buf), SubBlock_split(VARBUF_SB(buf), newsize)); + } + } + + return buf; +} + +void *IRO_calloc(size_t a, size_t b) { + void *buf; + size_t len = b * a; + buf = IRO_malloc(len); + if (buf) + memset(buf, 0, len); + return buf; +} + +void IRO_pool_free_all(void) { + int i; + Block *block; + if ((block = start_)) { + do { + block = block->next; + } while (block != start_); + start_ = NULL; + + for (i = 0; i < 4; i++) { + fix_start[i].a = NULL; + fix_start[i].b = NULL; + fix_start[i].count = 0; + } + } +} + +void IRO_InitializeAllocator(void) { + if (!initialized) { + int i; + for (i = 0; i < 4; i++) { + fix_start[i].a = NULL; + fix_start[i].b = NULL; + fix_start[i].count = 0; + } + start_ = NULL; + initialized = 1; + } +} + +void IRO_TerminateAllocator(void) { + initialized = 0; +} + diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.h b/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.h new file mode 100644 index 0000000..7700280 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.h @@ -0,0 +1,15 @@ +#ifndef COMPILER_IROMALLOC_H +#define COMPILER_IROMALLOC_H + +#include "IrOptimizer.h" + +extern size_t IRO_msize(void *buf); +extern void *IRO_malloc(size_t size); +extern void IRO_free(void *buf); +extern void *IRO_realloc(void *buf, size_t newsize); +extern void *IRO_calloc(size_t a, size_t b); +extern void IRO_pool_free_all(void); +extern void IRO_InitializeAllocator(void); +extern void IRO_TerminateAllocator(void); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.c b/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.c new file mode 100644 index 0000000..3f8989f --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.c @@ -0,0 +1,5734 @@ +#include "IroPointerAnalysis.h" +#include "IroEval.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroMalloc.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/CDecl.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CScope.h" +#include "compiler/InlineAsmPPC.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "IroPointerAnalysisADTs.c" + +// forward decls +static Object *GetLocalObject(PALocalVar *local, Object *proc, Boolean flag); +static Boolean GetActualLocsOfExtendedParam(LocationSetSet *set, LocationSet *ls, Object *var, Stack **stackPtr, ParamMappingFunction *map, Boolean flag); +static int ExpandLocationSetSetToActuals(Stack **stackPtr, ParamMappingFunction *map, LocationSetSet *thingsPointedTo); +static Boolean Lookup(LocationSetSet *set, Stack **stackPtr, Object *proc, ParamMappingFunction *map, PartialTransferFunction *ptf, LocationSet *dst, PointsToFunction *pointsToFunc, Boolean unk, Type *indRtype); +static ExtendedParam *CreateExtendedParam(Stack **stackPtr, ParamMappingFunction *map, Object *var, Boolean *result); +static Boolean Assign(PartialTransferFunction *ptf, LocationSet *dst, LocationSetSet *srcs, Object *proc, IROLinear *nd, IRONode *fnode); +static ObjectList *FunctionArguments(Object *proc); +static IRONode **FunctionNodeTable(Object *proc); +static Boolean ApplySummary(PartialTransferFunction *tgtPTF, ParamMappingFunction *tgtMap, Object *proc, IRONode *fnode, IROLinear *nd, PartialTransferFunction *ptf, ParamMappingFunction *map, Boolean flag); +static PartialTransferFunction *GetPTF(ParamMappingFunction *map, Object *proc, IROLinear *nd, PartialTransferFunction *ptf, Boolean *needVisit); +static Boolean ObjectIsAFunctionArgument(Object *proc, Object *obj); +static Boolean ObjectIsARealFunctionArgument(Object *proc, Object *obj); +static void EvalProc(Object *proc, ParamMappingFunction *map, PartialTransferFunction *ptf); +static void FindGlobalObjectAction(Object *object, void *refcon); + +static Boolean ObjectIsRestrictQualified(Object *obj) { + return (CParser_GetTypeQualifiers(obj->type, obj->qual) & Q_RESTRICT) != 0; +} + +static Boolean LocationIsVolatile(LocationSet *loc, Object *proc) { + Boolean result; + Type *rtype; + + IRO_ASSERT(932, loc != NULL); + IRO_ASSERT(933, proc != NULL); + + result = 0; + + if ((rtype = LocationSet_rtype(loc))) { + UInt32 qual; + switch (rtype->type) { + case TYPEARRAY: + qual = TYPE_POINTER(rtype)->qual; + break; + case TYPEPOINTER: + qual = TYPE_POINTER(rtype)->qual; + break; + case TYPEMEMBERPOINTER: + qual = TYPE_MEMBER_POINTER(rtype)->qual; + break; + default: + qual = 0; + } + if (qual & Q_VOLATILE) + result = 1; + } + + if (!result && !LocationSet_IsUnknown(loc)) { + Object *obj = NULL; + PAMemoryBlock *block = LocationSet_block(loc); + + switch (PAMemoryBlock_kind(block)) { + case PAMEMORYBLOCKKIND_LOCALVAR: { + PALocalVar *local = PAMemoryBlock_thing(block); + if (local) + obj = GetLocalObject(local, proc, 0); + break; + } + case PAMEMORYBLOCKKIND_EXTENDEDPARAM: { + ExtendedParam *ep = PAMemoryBlock_thing(block); + if (ep) { + ObjectSet *objSet = ExtendedParam_objectSet(ep); + if (objSet) { + if (ObjectSet_Count(objSet) == 1) + obj = ObjectSet_FindFirst(objSet); + else + ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj); + } + } + break; + } + } + + if (obj && is_volatile_object(obj)) + result = 1; + } + + return result; +} + +static Object *GetLocalObject(PALocalVar *local, Object *proc, Boolean flag) { + ObjectList *list; + Object *arg; + Object *obj; + char *name; + + IRO_ASSERT(999, local != NULL); + IRO_ASSERT(1000, proc != NULL); + + obj = PALocalVar_Get0_sub_4847E0(local); + name = PALocalVar_Get4_sub_4847D0(local); + + if (proc != &stUnknown && !obj && name && name[0] && flag) { + for (list = FunctionArguments(proc); list && !obj; list = list->next) { + arg = list->object; + if (arg && arg != &stUnknown && arg->name && arg->name->name) { + if (!strcmp(arg->name->name, name)) + obj = arg; + } + } + } + + if (obj) + PALocalVar_SetSth_sub_4847C0(local, obj); + + return obj; +} + +static Boolean ObjectIsAnExtendedParamCandidate(Object *obj) { + IRO_ASSERT(1042, obj != NULL); + + return Inline_IsObjectData(obj) || + obj->datatype == DABSOLUTE || + obj->datatype == DFUNC || + obj->datatype == DVFUNC || + obj->datatype == DINLINEFUNC; +} + +static Boolean ObjectIsAFunction(Object *obj) { + IRO_ASSERT(1054, obj != NULL); + + return obj->datatype == DFUNC || + obj->datatype == DVFUNC || + obj->datatype == DINLINEFUNC; +} + +static Boolean LocationSetRepresentsSingleLocation(LocationSet *ls, Object *proc, PointsToFunction *pointsToFunc) { + Boolean result; + PAMemoryBlock *mb; + PAMemoryBlockKind kind; + ExtendedParam *ep; + ObjectSet *objSet; + + IRO_ASSERT(1073, ls != NULL); + IRO_ASSERT(1074, proc == NULL || proc != NULL); + IRO_ASSERT(1075, pointsToFunc == NULL || pointsToFunc != NULL); + + result = 1; + if (LocationSet_IsUnknown(ls) || LocationSet_stride(ls)) { + result = 0; + } else { + mb = LocationSet_block(ls); + IRO_ASSERT(1084, mb != NULL); + + kind = PAMemoryBlock_kind(mb); + if (kind == PAMEMORYBLOCKKIND_HEAPBLOCK) { + result = 0; + } else if (kind == PAMEMORYBLOCKKIND_EXTENDEDPARAM) { + ep = PAMemoryBlock_thing(mb); + if (!ep) { + result = 0; + } else { + if ((objSet = ExtendedParam_objectSet(ep)) && ObjectSet_Count(objSet) > 1) { + Object *obj = NULL; + ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj); + + if (!obj) { + LocationSetSet *lss; + LocationSet *tmp; + ExtendedParam *ep; + ObjectSet *objSet; + + lss = LocationSetSet_New(); + LocationSetSet_Init(lss); + GetActualLocsOfExtendedParam(lss, ls, NULL, &stCallingContextStack, NULL, 0); + if ( + LocationSetSet_Count(lss) != 1 || + !(tmp = LocationSetSet_FindFirst(lss)) || + LocationSet_IsUnknown(tmp) || + (!((mb = LocationSet_block(tmp)) && (PAMemoryBlock_kind(mb) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) && (ep = PAMemoryBlock_thing(mb)) && (objSet = ExtendedParam_objectSet(ep)) && (ObjectSet_Count(objSet) == 1) && + ObjectIsAnExtendedParamCandidate(ObjectSet_FindFirst(objSet))) && + !LocationSetRepresentsSingleLocation(tmp, proc, pointsToFunc)) + ) + result = 0; + + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + } + } + } + } + } + + return result; +} + +static void EvalExprAction(LocationSet *ls, void *refcon) { + CInt64 value; + UInt32 stride; + PAMemoryBlock *mb; + + IRO_ASSERT(1151, ls != NULL); + IRO_ASSERT(1152, !LocationSet_IsUnknown(ls)); + IRO_ASSERT(1153, refcon != NULL); + + value = *((CInt64 *) refcon); + stride = LocationSet_stride(ls); + mb = LocationSet_block(ls); + + if (mb && PAMemoryBlock_kind(mb) == PAMEMORYBLOCKKIND_INT) { + Type *rtype = LocationSet_rtype(ls); + LocationSet_Term(ls); + value = CInt64_Add(value, *((CInt64 *) PAMemoryBlock_thing(mb))); + mb = PAMemoryBlock_New(); + PAMemoryBlock_Init(mb, PAMEMORYBLOCKKIND_INT, &value); + LocationSet_InitKnown(ls, mb, cint64_zero, stride, rtype); + } else { + value = CInt64_Add(value, LocationSet_field(ls)); + if (stride) { + CInt64 strideval; + CInt64_SetLong(&strideval, stride); + value = CInt64_Mod(value, strideval); + } + SetsLocationSetField_sub_4851B0(ls, value); + } +} + +static void EvalExprAction2(LocationSet *ls, void *refcon) { + UInt32 value; + + IRO_ASSERT(1188, ls != NULL); + IRO_ASSERT(1189, !LocationSet_IsUnknown(ls)); + IRO_ASSERT(1190, refcon != NULL); + + value = CInt64_GetULong((CInt64 *) refcon); + if (value) { + SetsLocationSetField_sub_4851B0(ls, CInt64_Mod(LocationSet_field(ls), *((CInt64 *) refcon))); + } + SetsLocationSetStride_sub_4852D0(ls, value); +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct EvalExprAction3Params { + LocationSetSet *set; + Stack **stackPtr; + Object *proc; + ParamMappingFunction *map; + PartialTransferFunction *ptf; + PointsToFunction *pointsToFunc; + Type *indRtype; + Boolean x1C; +} EvalExprAction3Params; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void EvalExprAction3(LocationSet *ls, void *refcon) { + EvalExprAction3Params *params; + + IRO_ASSERT(1219, ls != NULL); + IRO_ASSERT(1220, refcon != NULL); + + params = refcon; + + params->x1C |= Lookup( + params->set, + params->stackPtr, + params->proc, + params->map, + params->ptf, + ls, + params->pointsToFunc, + 1, + params->indRtype + ); +} + +static void EvalExprAction4(LocationSet *ls, void *refcon) { + Type *type; + PAMemoryBlock *mb; + + IRO_ASSERT(1235, ls != NULL); + IRO_ASSERT(1236, refcon != NULL); + + type = refcon; + + if (LocationSet_IsUnknown(ls)) { + LocationSet_SetRtype(ls, type); + } else if ((mb = LocationSet_block(ls))) { + if (PAMemoryBlock_kind(mb) == PAMEMORYBLOCKKIND_INT) { + CInt64 value; + CInt64 field; + UInt32 stride; + + value = *((CInt64 *) PAMemoryBlock_thing(mb)); + IRO_TruncateValueToType(&value, type); + field = LocationSet_field(ls); + IRO_TruncateValueToType(&field, type); + stride = LocationSet_stride(ls); + LocationSet_Term(ls); + + mb = PAMemoryBlock_New(); + PAMemoryBlock_Init(mb, PAMEMORYBLOCKKIND_INT, &value); + + LocationSet_InitKnown(ls, mb, field, stride, type); + } + LocationSet_SetRtype(ls, type); + } +} + +static Boolean EvalExpr(LocationSetSet *set, Object *proc, IROLinear *Int, Stack **stackPtr, ParamMappingFunction *map, PartialTransferFunction *ptf) { + Boolean result; + LocationSetSet *lss; + LocationSetSet *lss2; + IROLinear *indirect; + EvalExprAction3Params params; + IROLinear *originalInt; + + IRO_ASSERT(1284, set == NULL || set != NULL); + IRO_ASSERT(1285, proc != NULL); + IRO_ASSERT(1286, Int != NULL); + IRO_ASSERT(1287, map == NULL || map != NULL); + IRO_ASSERT(1288, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL); + + result = 0; + lss = LocationSetSet_New(); + LocationSetSet_Init(lss); + + originalInt = Int; + while (Int && Int->type == IROLinearOp1Arg && Int->nodetype == ETYPCON) + Int = Int->u.monadic; + + IRO_ASSERT(1302, Int != NULL); + + if (IRO_IsAssignment(Int)) { + if (Int->type == IROLinearOp1Arg) + indirect = Int->u.monadic; + else + indirect = Int->u.diadic.left; + IRO_ASSERT(1310, indirect->type == IROLinearOp1Arg && indirect->nodetype == EINDIRECT); + + lss2 = LocationSetSet_New(); + LocationSetSet_Init(lss2); + result |= EvalExpr(lss2, proc, indirect->u.monadic, stackPtr, map, ptf); + + memset(¶ms, 0, sizeof(params)); + params.set = lss; + params.stackPtr = stackPtr; + params.proc = proc; + params.map = map; + params.ptf = ptf; + if (Int->nodetype == EPOSTINC || Int->nodetype == EPOSTDEC) + params.pointsToFunc = indirect->pointsToFunction; + else + params.pointsToFunc = Int->pointsToFunction; + params.indRtype = indirect->rtype; + params.x1C = 0; + LocationSetSet_ForEach(lss2, EvalExprAction3, ¶ms); + result |= params.x1C; + LocationSetSet_Term(lss2); + LocationSetSet_Delete(lss2); + } else if (Int->type == IROLinearFunccall) { + IRO_ASSERT(1338, Int->u.funccall.returnedLocs != NULL); + LocationSetSet_AddSet(lss, Int->u.funccall.returnedLocs); + } else if (Int->type == IROLinearOp1Arg && Int->nodetype == EINDIRECT) { + lss2 = LocationSetSet_New(); + LocationSetSet_Init(lss2); + result |= EvalExpr(lss2, proc, Int->u.monadic, stackPtr, map, ptf); + + memset(¶ms, 0, sizeof(params)); + params.set = lss; + params.stackPtr = stackPtr; + params.proc = proc; + params.map = map; + params.ptf = ptf; + params.pointsToFunc = Int->pointsToFunction; + params.indRtype = Int->rtype; + params.x1C = 0; + LocationSetSet_ForEach(lss2, EvalExprAction3, ¶ms); + result |= params.x1C; + LocationSetSet_Term(lss2); + LocationSetSet_Delete(lss2); + } else if (Int->type == IROLinearOp2Arg && Int->nodetype == EADD) { + IROAddrRecord *addr = IRO_InitAddrRecordPointer(Int); + IRO_DecomposeAddressExpression(Int, addr); + if (addr->numObjRefs > 1) { + LocationSetSet_AddUnknown(lss, NULL, NULL, NULL); + } else { + CInt64 value; + CInt64 max; + CInt64 work; + Boolean flag1; + Boolean flag2; + + CInt64_SetLong(&value, 0); + flag1 = 0; + flag2 = 0; + if (addr->numObjRefs == 1) { + Object *obj; + IRO_ASSERT(1383, addr->objRefs->element->type == IROLinearOperand); + IRO_ASSERT(1384, addr->objRefs->element->u.node->type == EOBJREF); + obj = ((IROLinear *) addr->objRefs->element)->u.node->data.objref; + IRO_ASSERT(1387, obj != NULL); + result |= EvalExpr(lss, proc, addr->objRefs->element, stackPtr, map, ptf); + flag2 = 1; + } + + if (addr->numMisc != 0) { + IROElmList *list; + IROLinear *nd; + max = cint64_max; + + for (list = addr->misc; list; list = list->next) { + nd = list->element; + while (nd && nd->type == IROLinearOp1Arg && nd->nodetype == ETYPCON) + nd = nd->u.monadic; + + if (nd) { + if (nd->type == IROLinearOp2Arg && nd->nodetype == EMUL) { + if (IRO_IsIntConstant(nd->u.diadic.left) && IRO_IsIntConstant(nd->u.diadic.right)) { + if (IRO_IsUnsignedType(nd->rtype)) + work = CInt64_MulU(nd->u.diadic.left->u.node->data.intval, nd->u.diadic.right->u.node->data.intval); + else + work = CInt64_Mul(nd->u.diadic.left->u.node->data.intval, nd->u.diadic.right->u.node->data.intval); + IRO_TruncateValueToType(&work, ((IROLinear *) list->element)->rtype); + value = CInt64_Add(value, work); + } else if (IRO_IsIntConstant(nd->u.diadic.left)) { + work = nd->u.diadic.left->u.node->data.intval; + if (!CInt64_IsZero(&work) && CInt64_LessU(work, max)) + max = work; + } else if (IRO_IsIntConstant(nd->u.diadic.right)) { + work = nd->u.diadic.right->u.node->data.intval; + if (!CInt64_IsZero(&work) && CInt64_LessU(work, max)) + max = work; + } else { + max = cint64_one; + } + } else if (nd->type == IROLinearOp2Arg && nd->nodetype == ESHL) { + if (IRO_IsIntConstant(nd->u.diadic.left) && IRO_IsIntConstant(nd->u.diadic.right)) { + work = CInt64_Shl(nd->u.diadic.left->u.node->data.intval, nd->u.diadic.right->u.node->data.intval); + IRO_TruncateValueToType(&work, ((IROLinear *) list->element)->rtype); + value = CInt64_Add(value, work); + } else if (IRO_IsIntConstant(nd->u.diadic.right)) { + work = CInt64_Shl(cint64_one, nd->u.diadic.right->u.node->data.intval); + IRO_TruncateValueToType(&work, ((IROLinear *) list->element)->rtype); + if (!CInt64_IsZero(&work) && CInt64_LessU(work, max)) + max = work; + } else { + max = cint64_one; + } + } else { + LocationSet *tmp; + PAMemoryBlock *mb; + + lss2 = LocationSetSet_New(); + LocationSetSet_Init(lss2); + result |= EvalExpr(lss2, proc, nd, stackPtr, map, ptf); + + if (LocationSetSet_FindUnknown(lss2)) { + max = cint64_one; + } else if ( + LocationSetSet_Count(lss2) == 1 && + (tmp = LocationSetSet_FindFirst(lss2)) && + (LocationSet_stride(tmp) == 0) && + (mb = LocationSet_block(tmp)) && + (PAMemoryBlock_kind(mb) == PAMEMORYBLOCKKIND_INT) + ) { + value = CInt64_Add(value, *((CInt64 *) PAMemoryBlock_thing(mb))); + } else if (!flag2 && (IS_TYPE_POINTER(nd->rtype) || IS_TYPE_MEMBERPOINTER(nd->rtype))) { + if (flag1) { + LocationSetSet_RemoveAll(lss); + max = cint64_one; + } + LocationSetSet_AddSet(lss, lss2); + flag2 = 1; + } else if (IS_TYPE_POINTER(nd->rtype) || IS_TYPE_MEMBERPOINTER(nd->rtype)) { + LocationSetSet_AddUnknown(lss, NULL, NULL, NULL); + } else if (!flag1) { + LocationSetSet_AddSet(lss, lss2); + flag1 = 1; + } else { + LocationSetSet_AddUnknown(lss, NULL, NULL, NULL); + } + LocationSetSet_Term(lss2); + LocationSetSet_Delete(lss2); + } + } + } + + if (IS_TYPE_POINTER(Int->rtype)) + CInt64_SetLong(&work, TYPE_POINTER(Int->rtype)->target->size); + else if (IS_TYPE_MEMBERPOINTER(Int->rtype)) + CInt64_SetLong(&work, TYPE_MEMBER_POINTER(Int->rtype)->ty1->size); + else + work = cint64_zero; + + if (CInt64_GreaterU(work, max)) + max = work; + } + + if (addr->numInts != 0) { + IROElmList *list; + IROLinear *addend; + + for (list = addr->ints; list; list = list->next) { + addend = list->element; + + if (addend) { + IRO_ASSERT(1536, IRO_IsIntConstant(addend)); + + value = CInt64_Add(value, addend->u.node->data.intval); + } + } + } + + IRO_TruncateValueToType(&value, Int->rtype); + + if (LocationSetSet_Count(lss) == 0) { + if (CInt64_Equal(max, cint64_max)) { + PAMemoryBlock *mb; + LocationSet *ls; + + mb = PAMemoryBlock_New(); + PAMemoryBlock_Init(mb, PAMEMORYBLOCKKIND_INT, &value); + + ls = LocationSet_New(); + LocationSet_InitKnown(ls, mb, cint64_zero, 0, Int->rtype); + LocationSetSet_Add(lss, ls); + LocationSet_Term(ls); + LocationSet_Delete(ls); + } else { + LocationSetSet_AddUnknown(lss, NULL, NULL, NULL); + } + } else { + if (!LocationSetSet_FindUnknown(lss) && !CInt64_IsZero(&value)) + LocationSetSet_ForEach(lss, EvalExprAction, &value); + } + + if (!LocationSetSet_FindUnknown(lss) && addr->numMisc && !CInt64_Equal(max, cint64_max)) + LocationSetSet_ForEach(lss, EvalExprAction2, &max); + } + } else if (Int->type == IROLinearOperand) { + Object *obj; + void *thing; + PAMemoryBlockKind kind; + + thing = NULL; + if (IRO_IsIntConstant(Int)) { + kind = PAMEMORYBLOCKKIND_INT; + thing = &Int->u.node->data.intval; + } else if (Int->u.node->type == ESTRINGCONST) { + kind = PAMEMORYBLOCKKIND_6; + thing = Int->u.node; + } else if (Int->u.node->type == EOBJREF) { + obj = Int->u.node->data.objref; + IRO_ASSERT(1597, obj != NULL); + if (ObjectIsAnExtendedParamCandidate(obj)) { + kind = PAMEMORYBLOCKKIND_EXTENDEDPARAM; + thing = CreateExtendedParam(stackPtr, map, obj, &result); + } else { + kind = PAMEMORYBLOCKKIND_LOCALVAR; + thing = PALocalVar_New(); + if (obj->name && obj->name->name && ObjectIsARealFunctionArgument(proc, obj)) + PALocalVar_InitByName(thing, obj->name->name); + else + PALocalVar_InitByObject(thing, obj); + } + } + + if (thing) { + PAMemoryBlock *mb; + LocationSet *ls; + + mb = PAMemoryBlock_New(); + PAMemoryBlock_Init(mb, kind, thing); + + ls = LocationSet_New(); + LocationSet_InitKnown(ls, mb, cint64_zero, 0, Int->rtype); + LocationSetSet_Add(lss, ls); + LocationSet_Term(ls); + LocationSet_Delete(ls); + } + } else if (Int->type == IROLinearOp1Arg && Int->nodetype == EBITFIELD) { + LocationSet *ls; + + lss2 = LocationSetSet_New(); + LocationSetSet_Init(lss2); + result |= EvalExpr(lss2, proc, Int->u.monadic, stackPtr, map, ptf); + + if (LocationSetSet_Count(lss2) == 1 && (ls = LocationSetSet_FindFirst(lss2))) + LocationSetSet_AddUnknown(lss, NULL, NULL, ls); + else + CError_FATAL(1643); + + LocationSetSet_Term(lss2); + LocationSetSet_Delete(lss2); + } else { + LocationSetSet_AddUnknown(lss, NULL, NULL, NULL); + } + + LocationSetSet_ForEach(lss, EvalExprAction4, originalInt->rtype); + + if (set && lss) + LocationSetSet_AddSet(set, lss); + + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + + return result; +} + +static IROAddrRecord *IRO_InitENodeAddrRecordPointer(ENode *enode) { + IROAddrRecord *addr = IRO_malloc(sizeof(IROAddrRecord)); + + addr->numObjRefs = 0; + addr->objRefs = NULL; + addr->numMisc = 0; + addr->misc = NULL; + addr->numInts = 0; + addr->ints = NULL; + addr->x16 = 0; + addr->linear = (IROLinear *) enode; + + return addr; +} + +static void IRO_AddENodeElmToList(ENode *linear, IROElmList **list) { + IROElmList *elmlist = IRO_malloc(sizeof(IROElmList)); + elmlist->element = linear; + elmlist->next = NULL; + if (!*list) { + *list = elmlist; + } else { + elmlist->next = *list; + *list = elmlist; + } +} + +static void IRO_DecomposeENodeAddressExpression(ENode *node, IROAddrRecord *addr) { + if (node->data.diadic.left->type == EADD) { + IRO_DecomposeENodeAddressExpression(node->data.diadic.left, addr); + } else if (node->data.diadic.left->type == EINTCONST) { + addr->numInts++; + IRO_AddENodeElmToList(node->data.diadic.left, &addr->ints); + } else if (node->data.diadic.left->type == EOBJREF) { + addr->numObjRefs++; + IRO_AddENodeElmToList(node->data.diadic.left, &addr->objRefs); + } else { + addr->numMisc++; + IRO_AddENodeElmToList(node->data.diadic.left, &addr->misc); + } + + if (node->data.diadic.right->type == EADD) { + IRO_DecomposeENodeAddressExpression(node->data.diadic.right, addr); + } else if (node->data.diadic.right->type == EINTCONST) { + addr->numInts++; + IRO_AddENodeElmToList(node->data.diadic.right, &addr->ints); + } else if (node->data.diadic.right->type == EOBJREF) { + addr->numObjRefs++; + IRO_AddENodeElmToList(node->data.diadic.right, &addr->objRefs); + } else { + addr->numMisc++; + IRO_AddENodeElmToList(node->data.diadic.right, &addr->misc); + } +} + +static Boolean EvalENodeExpr(LocationSetSet *set, Object *proc, ENode *Int, Stack **stackPtr, ParamMappingFunction *map, PartialTransferFunction *ptf) { + Boolean result; + LocationSetSet *lss; + LocationSetSet *lss2; + ENode *indirect; + EvalExprAction3Params params; + ENode *originalInt; + + IRO_ASSERT(0, set == NULL || set != NULL); + IRO_ASSERT(0, proc != NULL); + IRO_ASSERT(0, Int != NULL); + IRO_ASSERT(0, map == NULL || map != NULL); + IRO_ASSERT(0, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL); + + result = 0; + lss = LocationSetSet_New(); + LocationSetSet_Init(lss); + + originalInt = Int; + while (Int && Int->type == ETYPCON) + Int = Int->data.monadic; + + IRO_ASSERT(0, Int != NULL); + + if (IRO_IsAssignOp[Int->type]) { + if (Int->type == EPOSTINC || Int->type == EPOSTDEC || Int->type == EPREINC || Int->type == EPREDEC) + indirect = Int->data.monadic; + else + indirect = Int->data.diadic.left; + IRO_ASSERT(0, indirect->type == EINDIRECT); + + lss2 = LocationSetSet_New(); + LocationSetSet_Init(lss2); + result |= EvalENodeExpr(lss2, proc, indirect->data.monadic, stackPtr, map, ptf); + + memset(¶ms, 0, sizeof(params)); + params.set = lss; + params.stackPtr = stackPtr; + params.proc = proc; + params.map = map; + params.ptf = ptf; + if (Int->type == EPOSTINC || Int->type == EPOSTDEC) + params.pointsToFunc = indirect->pointsTo; + else + params.pointsToFunc = Int->pointsTo; + params.indRtype = indirect->rtype; + params.x1C = 0; + LocationSetSet_ForEach(lss2, EvalExprAction3, ¶ms); + result |= params.x1C; + LocationSetSet_Term(lss2); + LocationSetSet_Delete(lss2); + } else if (Int->type == EINDIRECT) { + lss2 = LocationSetSet_New(); + LocationSetSet_Init(lss2); + result |= EvalENodeExpr(lss2, proc, Int->data.monadic, stackPtr, map, ptf); + + memset(¶ms, 0, sizeof(params)); + params.set = lss; + params.stackPtr = stackPtr; + params.proc = proc; + params.map = map; + params.ptf = ptf; + params.pointsToFunc = Int->pointsTo; + params.indRtype = Int->rtype; + params.x1C = 0; + LocationSetSet_ForEach(lss2, EvalExprAction3, ¶ms); + result |= params.x1C; + LocationSetSet_Term(lss2); + LocationSetSet_Delete(lss2); + } else if (Int->type == EADD) { + IROAddrRecord *addr = IRO_InitENodeAddrRecordPointer(Int); + IRO_DecomposeENodeAddressExpression(Int, addr); + if (addr->numObjRefs > 1) { + LocationSetSet_AddUnknown(lss, NULL, NULL, NULL); + } else { + CInt64 value; + CInt64 max; + CInt64 work; + Boolean flag1; + Boolean flag2; + + CInt64_SetLong(&value, 0); + flag1 = 0; + flag2 = 0; + if (addr->numObjRefs == 1) { + Object *obj; + // IRO_ASSERT(addr->objRefs->element->type == IROLinearOperand); + // IRO_ASSERT(addr->objRefs->element->u.node->type == EOBJREF); + obj = ((ENode *) addr->objRefs->element)->data.objref; + IRO_ASSERT(0, obj != NULL); + result |= EvalENodeExpr(lss, proc, addr->objRefs->element, stackPtr, map, ptf); + flag2 = 1; + } + + if (addr->numMisc != 0) { + IROElmList *list; + ENode *nd; + max = cint64_max; + + for (list = addr->misc; list; list = list->next) { + nd = list->element; + while (nd && nd->type == ETYPCON) + nd = nd->data.monadic; + + if (nd) { + if (nd->type == EMUL) { + if (nd->data.diadic.left->type == EINTCONST && nd->data.diadic.right->type == EINTCONST) { + if (IRO_IsUnsignedType(nd->rtype)) + work = CInt64_MulU(nd->data.diadic.left->data.intval, + nd->data.diadic.right->data.intval); + else + work = CInt64_Mul(nd->data.diadic.left->data.intval, + nd->data.diadic.right->data.intval); + IRO_TruncateValueToType(&work, ((ENode *) list->element)->rtype); + value = CInt64_Add(value, work); + } else if (nd->data.diadic.left->type == EINTCONST) { + work = nd->data.diadic.left->data.intval; + if (!CInt64_IsZero(&work) && CInt64_LessU(work, max)) + max = work; + } else if (nd->data.diadic.right->type == EINTCONST) { + work = nd->data.diadic.right->data.intval; + if (!CInt64_IsZero(&work) && CInt64_LessU(work, max)) + max = work; + } else { + max = cint64_one; + } + } else if (nd->type == ESHL) { + if (nd->data.diadic.left->type == EINTCONST && nd->data.diadic.right->type == EINTCONST) { + work = CInt64_Shl(nd->data.diadic.left->data.intval, + nd->data.diadic.right->data.intval); + IRO_TruncateValueToType(&work, ((ENode *) list->element)->rtype); + value = CInt64_Add(value, work); + } else if (nd->data.diadic.right->type == EINTCONST) { + work = CInt64_Shl(cint64_one, nd->data.diadic.right->data.intval); + IRO_TruncateValueToType(&work, ((ENode *) list->element)->rtype); + if (!CInt64_IsZero(&work) && CInt64_LessU(work, max)) + max = work; + } else { + max = cint64_one; + } + } else { + LocationSet *tmp; + PAMemoryBlock *mb; + + lss2 = LocationSetSet_New(); + LocationSetSet_Init(lss2); + result |= EvalENodeExpr(lss2, proc, nd, stackPtr, map, ptf); + + if (LocationSetSet_FindUnknown(lss2)) { + max = cint64_one; + } else if ( + LocationSetSet_Count(lss2) == 1 && + (tmp = LocationSetSet_FindFirst(lss2)) && + (LocationSet_stride(tmp) == 0) && + (mb = LocationSet_block(tmp)) && + (PAMemoryBlock_kind(mb) == PAMEMORYBLOCKKIND_INT) + ) { + value = CInt64_Add(value, *((CInt64 *) PAMemoryBlock_thing(mb))); + } else if (!flag2 && (IS_TYPE_POINTER(nd->rtype) || IS_TYPE_MEMBERPOINTER(nd->rtype))) { + if (flag1) { + LocationSetSet_RemoveAll(lss); + max = cint64_one; + } + LocationSetSet_AddSet(lss, lss2); + flag2 = 1; + } else if (IS_TYPE_POINTER(nd->rtype) || IS_TYPE_MEMBERPOINTER(nd->rtype)) { + LocationSetSet_AddUnknown(lss, NULL, NULL, NULL); + } else if (!flag1) { + LocationSetSet_AddSet(lss, lss2); + flag1 = 1; + } else { + LocationSetSet_AddUnknown(lss, NULL, NULL, NULL); + } + LocationSetSet_Term(lss2); + LocationSetSet_Delete(lss2); + } + } + } + + if (IS_TYPE_POINTER(Int->rtype)) + CInt64_SetLong(&work, TYPE_POINTER(Int->rtype)->target->size); + else if (IS_TYPE_MEMBERPOINTER(Int->rtype)) + CInt64_SetLong(&work, TYPE_MEMBER_POINTER(Int->rtype)->ty1->size); + else + work = cint64_zero; + + if (CInt64_GreaterU(work, max)) + max = work; + } + + if (addr->numInts != 0) { + IROElmList *list; + ENode *addend; + + for (list = addr->ints; list; list = list->next) { + addend = list->element; + + if (addend) { + IRO_ASSERT(0, addend->type == EINTCONST); + + value = CInt64_Add(value, addend->data.intval); + } + } + } + + IRO_TruncateValueToType(&value, Int->rtype); + + if (LocationSetSet_Count(lss) == 0) { + if (CInt64_Equal(max, cint64_max)) { + PAMemoryBlock *mb; + LocationSet *ls; + + mb = PAMemoryBlock_New(); + PAMemoryBlock_Init(mb, PAMEMORYBLOCKKIND_INT, &value); + + ls = LocationSet_New(); + LocationSet_InitKnown(ls, mb, cint64_zero, 0, Int->rtype); + LocationSetSet_Add(lss, ls); + LocationSet_Term(ls); + LocationSet_Delete(ls); + } else { + LocationSetSet_AddUnknown(lss, NULL, NULL, NULL); + } + } else { + if (!LocationSetSet_FindUnknown(lss) && !CInt64_IsZero(&value)) + LocationSetSet_ForEach(lss, EvalExprAction, &value); + } + + if (!LocationSetSet_FindUnknown(lss) && addr->numMisc && !CInt64_Equal(max, cint64_max)) + LocationSetSet_ForEach(lss, EvalExprAction2, &max); + } + } else if (Int->type == EOBJREF || Int->type == EINTCONST || Int->type == ESTRINGCONST) { + Object *obj; + void *thing; + PAMemoryBlockKind kind; + + thing = NULL; + if (Int->type == EINTCONST) { + kind = PAMEMORYBLOCKKIND_INT; + thing = &Int->data.intval; + } else if (Int->type == ESTRINGCONST) { + kind = PAMEMORYBLOCKKIND_6; + thing = Int; + } else if (Int->type == EOBJREF) { + obj = Int->data.objref; + IRO_ASSERT(0, obj != NULL); + if (ObjectIsAnExtendedParamCandidate(obj)) { + kind = PAMEMORYBLOCKKIND_EXTENDEDPARAM; + thing = CreateExtendedParam(stackPtr, map, obj, &result); + } else { + kind = PAMEMORYBLOCKKIND_LOCALVAR; + thing = PALocalVar_New(); + if (obj->name && obj->name->name && ObjectIsARealFunctionArgument(proc, obj)) + PALocalVar_InitByName(thing, obj->name->name); + else + PALocalVar_InitByObject(thing, obj); + } + } + + if (thing) { + PAMemoryBlock *mb; + LocationSet *ls; + + mb = PAMemoryBlock_New(); + PAMemoryBlock_Init(mb, kind, thing); + + ls = LocationSet_New(); + LocationSet_InitKnown(ls, mb, cint64_zero, 0, Int->rtype); + LocationSetSet_Add(lss, ls); + LocationSet_Term(ls); + LocationSet_Delete(ls); + } + } else if (Int->type == EBITFIELD) { + LocationSet *ls; + + lss2 = LocationSetSet_New(); + LocationSetSet_Init(lss2); + result |= EvalENodeExpr(lss2, proc, Int->data.monadic, stackPtr, map, ptf); + + if (LocationSetSet_Count(lss2) == 1 && (ls = LocationSetSet_FindFirst(lss2))) + LocationSetSet_AddUnknown(lss, NULL, NULL, ls); + else + CError_FATAL(2146); + + LocationSetSet_Term(lss2); + LocationSetSet_Delete(lss2); + } else { + LocationSetSet_AddUnknown(lss, NULL, NULL, NULL); + } + + LocationSetSet_ForEach(lss, EvalExprAction4, originalInt->rtype); + + if (set && lss) + LocationSetSet_AddSet(set, lss); + + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + + return result; +} + +static Boolean EvalVarAddr(LocationSetSet *set, Object *proc, VarRecord *var, Stack **stackPtr, ParamMappingFunction *map) { + Boolean result; + PAMemoryBlockKind kind; + void *thing; + Object *obj; + PAMemoryBlock *block; + LocationSet *loc; + + result = 0; + obj = var->object; + + if (ObjectIsAnExtendedParamCandidate(obj)) { + kind = PAMEMORYBLOCKKIND_EXTENDEDPARAM; + thing = CreateExtendedParam(stackPtr, map, obj, &result); + } else { + kind = PAMEMORYBLOCKKIND_LOCALVAR; + thing = PALocalVar_New(); + if (obj->name && obj->name->name && ObjectIsAFunctionArgument(proc, obj)) + PALocalVar_InitByName(thing, obj->name->name); + else + PALocalVar_InitByObject(thing, obj); + } + + block = PAMemoryBlock_New(); + PAMemoryBlock_Init(block, kind, thing); + + loc = LocationSet_New(); + LocationSet_InitKnown(loc, block, cint64_zero, 0, CDecl_NewPointerType(obj->type)); + LocationSetSet_Add(set, loc); + LocationSet_Term(loc); + LocationSet_Delete(loc); + + return result; +} + +static Boolean EvalVariable(LocationSetSet *set, Object *proc, VarRecord *var, PointsToFunction *pointsToFunc, Stack **stackPtr, ParamMappingFunction *map, PartialTransferFunction *ptf) { + LocationSetSet *locs; + Boolean result; + EvalExprAction3Params params; + + locs = LocationSetSet_New(); + LocationSetSet_Init(locs); + result = EvalVarAddr(locs, proc, var, stackPtr, map); + + memset(¶ms, 0, sizeof(params)); + params.set = set; + params.stackPtr = stackPtr; + params.proc = proc; + params.map = map; + params.ptf = ptf; + params.pointsToFunc = pointsToFunc; + params.indRtype = var->object->type; + params.x1C = 0; + LocationSetSet_ForEach(locs, EvalExprAction3, ¶ms); + + result |= params.x1C; + LocationSetSet_Term(locs); + LocationSetSet_Delete(locs); + + return result; +} + +static void StoreReturnedLocationsAction(LocationSet *loc, void *refcon) { + IRO_ASSERT(2275, loc != NULL); + IRO_ASSERT(2276, refcon != NULL); + + if (!LocationSet_IsUnknown(loc)) { + if (PAMemoryBlock_kind(LocationSet_block(loc)) == PAMEMORYBLOCKKIND_HEAPBLOCK) { + PAHeapBlock *hb; + PAMemoryBlock *mb; + CInt64 field; + UInt32 stride; + Type *rtype; + + hb = CreateUniqueHeapAlloc_sub_486420(); + InitUniqueHeapAlloc_sub_486410(hb, refcon); + + mb = PAMemoryBlock_New(); + PAMemoryBlock_Init(mb, PAMEMORYBLOCKKIND_HEAPBLOCK, hb); + + field = LocationSet_field(loc); + stride = LocationSet_stride(loc); + rtype = LocationSet_rtype(loc); + LocationSet_Term(loc); + LocationSet_InitKnown(loc, mb, field, stride, rtype); + } + } +} + +static void StoreReturnedLocations(IROLinear *nd, PartialTransferFunction *ptf, ParamMappingFunction *map) { + LocationSet *retLoc; + LocationSetSet *retLocs; + + IRO_ASSERT(2307, nd != NULL); + IRO_ASSERT(2308, nd->type == IROLinearFunccall); + IRO_ASSERT(2309, ptf != NULL); + IRO_ASSERT(2310, map != NULL); + + retLoc = PartialTransferFunction_returnLocation(ptf); + retLocs = nd->u.funccall.returnedLocs; + if (!retLocs) { + LocationSetSet_Init(retLocs = nd->u.funccall.returnedLocs = LocationSetSet_New()); + } else { + LocationSetSet_RemoveAll(retLocs); + } + + Lookup(retLocs, NULL, NULL, NULL, NULL, retLoc, PartialTransferFunction_finalPointsToFn(ptf), 0, NULL); + ExpandLocationSetSetToActuals(&stCallingContextStack, map, retLocs); + LocationSetSet_ForEach(retLocs, StoreReturnedLocationsAction, nd); +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct EPParams { + ParamMappingFunction *map; + ExtendedParam *ep; + Object *proc; + Object *var; + unsigned char x10; + unsigned char x11; +} EPParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void FillInAppropriateMappingsWithExtParamAction(Object *obj, void *refcon) { + EPParams *params; + ParamMapping *mapping; + + IRO_ASSERT(2352, obj != NULL); + IRO_ASSERT(2353, refcon != NULL); + + params = refcon; + + IRO_ASSERT(2357, params->map != NULL); + IRO_ASSERT(2358, params->ep != NULL); + IRO_ASSERT(2359, params->proc == NULL || params->proc != NULL); + IRO_ASSERT(2360, params->proc != &stUnknown); + IRO_ASSERT(2361, params->var == NULL || params->var != NULL); + IRO_ASSERT(2362, params->var != &stUnknown); + + mapping = ParamMappingFunction_FindMappingByFormal(params->map, obj); + if (!mapping) { + if (ObjectIsAnExtendedParamCandidate(obj) || !params->proc || ObjectIsAFunctionArgument(params->proc, obj)) { + mapping = ParamMapping_New(); + ParamMapping_Init_PROBABLY(mapping, NULL, obj, params->ep); + Pmf_Add_sub_486610(params->map, mapping); + ParamMapping_Term(mapping); + ParamMapping_Delete(mapping); + params->x11 = 1; + } + } else { + if (ParamMapping_extended(mapping) != params->ep) { + ParamMapping_SetExtended(mapping, params->ep); + params->x11 = 1; + } + } + + if (obj == params->var) + params->x10 = 1; +} + +static Boolean FillInAppropriateMappingsWithExtParam(ParamMappingFunction *map, Object *var, ExtendedParam *ep, Object *proc) { + EPParams params; + ObjectSet *objSet; + + IRO_ASSERT(2398, map != NULL); + IRO_ASSERT(2399, var == NULL || var != NULL); + IRO_ASSERT(2400, var != &stUnknown); + IRO_ASSERT(2401, ep != NULL); + IRO_ASSERT(2402, proc == NULL || proc != NULL); + IRO_ASSERT(2403, proc != &stUnknown); + + memset(¶ms, 0, sizeof(params)); + params.map = map; + params.ep = ep; + params.proc = proc; + params.var = var; + params.x10 = 0; + params.x11 = 0; + + if ((objSet = ExtendedParam_objectSet(ep))) + ObjectSet_ForEach(objSet, FillInAppropriateMappingsWithExtParamAction, ¶ms); + + if (var && !params.x10) { + ExtendedParam_sub_4867B0(ep, var); + FillInAppropriateMappingsWithExtParamAction(var, ¶ms); + } + + return params.x11; +} + +static void MatchPTFHelper(LocationSet *loc, LocationSetSet *locs, Object *proc, ParamMappingFunction *map, PartialTransferFunction *ptf) { + PointsToFunction *initial; + PAMemoryBlock *block; + PAMemoryBlockKind kind; + Object *obj; + + IRO_ASSERT(2448, loc != NULL); + IRO_ASSERT(2449, !LocationSet_IsUnknown(loc)); + IRO_ASSERT(2450, locs != NULL); + IRO_ASSERT(2451, proc != NULL); + IRO_ASSERT(2452, map != NULL); + IRO_ASSERT(2453, ptf != NULL); + + initial = PartialTransferFunction_initialPointsToFn(ptf); + IRO_ASSERT(2456, initial != NULL); + + IRO_ASSERT(2458, !LocationSet_IsUnknown(loc)); + + block = LocationSet_block(loc); + IRO_ASSERT(2460, block != NULL); + + kind = PAMemoryBlock_kind(block); + + if (kind == PAMEMORYBLOCKKIND_LOCALVAR) { + PALocalVar *local; + + local = PAMemoryBlock_thing(block); + IRO_ASSERT(2466, local != NULL); + + obj = GetLocalObject(local, proc, 1); + if (obj && ObjectIsAFunctionArgument(proc, obj)) { + if (LocationSetSet_Count(locs) == 1) { + LocationSet *ls; + ls = LocationSetSet_FindFirst(locs); + if (ls && !LocationSet_IsUnknown(ls)) { + if ((block = LocationSet_block(ls))) { + if (PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) { + ExtendedParam *ep; + if ((ep = PAMemoryBlock_thing(block))) { + ExtendedParam_sub_4867B0(ep, obj); + if (stExtParamSet) + ExtParamSet_sub_487630(stExtParamSet, ep); + FillInAppropriateMappingsWithExtParam(map, obj, ep, proc); + } + } + } + } + } + } + } else if (kind == PAMEMORYBLOCKKIND_EXTENDEDPARAM) { + void *ep = PAMemoryBlock_thing(block); + IRO_ASSERT(2489, ep != NULL); + + obj = NULL; + ObjectSet_ForEach(ExtendedParam_objectSet(ep), FindGlobalObjectAction, &obj); + if (obj && obj != &stUnknown) + FillInAppropriateMappingsWithExtParam(map, obj, ep, proc); + } else { + CError_FATAL(2500); + } + + if (!PointsToFunction_FindByLookupCompatibleLocationSet(initial, loc)) { + PointsToEntry *pte = PointsToEntry_New(); + PointsToEntry_Init(pte, loc, locs); + PointsToFunction_AddWithoutChecking(initial, pte); + PointsToEntry_Term(pte); + PointsToEntry_Delete(pte); + } +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct MatchPTFActionParams { + Object *proc; + PartialTransferFunction *ptfCopy; + ParamMappingFunction *mapCopy; + Stack **stackPtr; +} MatchPTFActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void MatchPTFAction1(PointsToEntry *tgtPTE, void *refcon) { + MatchPTFActionParams *params; + LocationSet *loc; + LocationSetSet *locs; + PAMemoryBlock *block; + PAMemoryBlockKind kind; + + IRO_ASSERT(2525, tgtPTE != NULL); + IRO_ASSERT(2526, refcon != NULL); + + params = refcon; + + IRO_ASSERT(2530, params->proc != NULL); + IRO_ASSERT(2531, params->ptfCopy != NULL); + IRO_ASSERT(2532, params->mapCopy != NULL); + + if ((loc = PointsToEntry_loc(tgtPTE)) && (locs = PointsToEntry_locs(tgtPTE))) { + if ((block = LocationSet_block(loc))) { + kind = PAMemoryBlock_kind(block); + if (kind == PAMEMORYBLOCKKIND_LOCALVAR) { + MatchPTFHelper(loc, locs, params->proc, params->mapCopy, params->ptfCopy); + } else if (kind != PAMEMORYBLOCKKIND_EXTENDEDPARAM) { + CError_FATAL(2547); + } + } + } +} + +static void MatchPTFAction2(PointsToEntry *tgtPTE, void *refcon) { + MatchPTFActionParams *params; + LocationSet *loc; + LocationSetSet *locs; + PAMemoryBlock *block; + PAMemoryBlockKind kind; + + IRO_ASSERT(2561, tgtPTE != NULL); + IRO_ASSERT(2562, refcon != NULL); + + params = refcon; + + IRO_ASSERT(2566, params->proc != NULL); + IRO_ASSERT(2567, params->ptfCopy != NULL); + IRO_ASSERT(2568, params->mapCopy != NULL); + + if ((loc = PointsToEntry_loc(tgtPTE)) && (locs = PointsToEntry_locs(tgtPTE))) { + if ((block = LocationSet_block(loc))) { + kind = PAMemoryBlock_kind(block); + if (kind == PAMEMORYBLOCKKIND_EXTENDEDPARAM) { + MatchPTFHelper(loc, locs, params->proc, params->mapCopy, params->ptfCopy); + } + } + } +} + +static Boolean MatchPTF(PartialTransferFunction *tgtPTF, Object *proc, ParamMappingFunction *map, IROLinear *nd, PartialTransferFunction *ptf) { + Boolean result; + PartialTransferFunction *ptfCopy; + ParamMappingFunction *mapCopy; + PointsToFunction *initial; + MatchPTFActionParams params; + + IRO_ASSERT(2593, tgtPTF != NULL); + IRO_ASSERT(2594, proc != NULL); + IRO_ASSERT(2595, map != NULL); + IRO_ASSERT(2596, nd != NULL); + IRO_ASSERT(2597, ptf != NULL); + + ptfCopy = PartialTransferFunction_New(); + PartialTransferFunction_Copy(ptfCopy, ptf); + + mapCopy = ParamMappingFunction_New(); + ParamMappingFunction_Copy(mapCopy, map); + + initial = PartialTransferFunction_initialPointsToFn(tgtPTF); + PointsToFunction_SortByExtendedParamNum(initial); + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.ptfCopy = ptfCopy; + params.mapCopy = mapCopy; + params.stackPtr = &stCallingContextStack; + + PointsToFunction_ForEach(initial, MatchPTFAction1, ¶ms); + PointsToFunction_ForEach(initial, MatchPTFAction2, ¶ms); + + result = PointsToFunctions_Match(initial, PartialTransferFunction_initialPointsToFn(ptfCopy)); + if (result) { + PartialTransferFunction_Term(ptf); + PartialTransferFunction_Copy(ptf, ptfCopy); + + ParamMappingFunction_Term(map); + ParamMappingFunction_Copy(map, mapCopy); + } + + PartialTransferFunction_Term(ptfCopy); + PartialTransferFunction_Delete(ptfCopy); + + ParamMappingFunction_Term(mapCopy); + ParamMappingFunction_Delete(mapCopy); + + return result; +} + +static void FindCallTargetsAction2(Object *obj, void *refcon) { + ObjectSet *procList; + + IRO_ASSERT(2650, obj != NULL); + IRO_ASSERT(2651, refcon != NULL); + + procList = refcon; + + if (obj == &stUnknown || ObjectIsAFunction(obj)) + ObjectSet_sub_4867D0(procList, obj); +} + +static void FindCallTargetsAction(LocationSet *ls, void *refcon) { + ObjectSet *procList; + + IRO_ASSERT(2669, ls != NULL); + IRO_ASSERT(2670, refcon != NULL); + + procList = refcon; + + if (!LocationSet_IsUnknown(ls)) { + PAMemoryBlock *mb = LocationSet_block(ls); + if (PAMemoryBlock_kind(mb) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) { + ExtendedParam *ep = PAMemoryBlock_thing(mb); + ObjectSet *objSet = ExtendedParam_objectSet(ep); + ObjectSet_ForEach(objSet, FindCallTargetsAction2, procList); + } + } else { + FindCallTargetsAction2(&stUnknown, procList); + } +} + +static int FindCallTargets(ObjectSet *procList, Object *proc, IROLinear *nd, ParamMappingFunction *map, PartialTransferFunction *ptf) { + LocationSetSet *set; + int evalResult; + int result; + + IRO_ASSERT(2696, procList != NULL); + IRO_ASSERT(2697, proc != NULL); + IRO_ASSERT(2698, nd != NULL); + IRO_ASSERT(2699, nd->type == IROLinearFunccall); + IRO_ASSERT(2700, map != NULL); + IRO_ASSERT(2701, ptf != NULL); + + set = LocationSetSet_New(); + LocationSetSet_Init(set); + evalResult = EvalExpr(set, proc, nd->u.funccall.linear8, &stCallingContextStack, map, ptf); + result = evalResult | ExpandLocationSetSetToActuals(&stCallingContextStack, map, set); + LocationSetSet_ForEach(set, FindCallTargetsAction, procList); + LocationSetSet_Term(set); + LocationSetSet_Delete(set); + + return result; +} + +static int LookupParam(LocationSetSet *set, LocationSet *ls, Object *var, Stack **stackPtr, Object *proc, ParamMappingFunction *map, PartialTransferFunction *ptf, Boolean unkflag) { + Boolean result; + ExtendedParam *ep; + + IRO_ASSERT(2728, set == NULL || set != NULL); + IRO_ASSERT(2729, ls != NULL); + IRO_ASSERT(2730, var != NULL); + IRO_ASSERT(2731, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL); + IRO_ASSERT(2732, proc != NULL); + IRO_ASSERT(2733, map == NULL || map != NULL); + IRO_ASSERT(2734, ptf == NULL || ptf != NULL); + + result = 0; + + ep = ExtendedParam_FindByObject(var); + if (!ep) + ep = CreateExtendedParam(stackPtr, map, var, &result); + + IRO_ASSERT(2741, ep != NULL); + + if (ep) { + PAMemoryBlock *block; + LocationSet *newLS; + + block = PAMemoryBlock_New(); + PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_EXTENDEDPARAM, ep); + + newLS = LocationSet_New(); + LocationSet_InitKnown(newLS, block, LocationSet_field(ls), LocationSet_stride(ls), LocationSet_rtype(ls)); + if (set) + LocationSetSet_Add(set, newLS); + + if (unkflag) { + if (map) + result |= FillInAppropriateMappingsWithExtParam(map, var, ep, proc); + + if (ptf) { + PointsToFunction *initial; + + initial = PartialTransferFunction_initialPointsToFn(ptf); + if (initial && !PointsToFunction_FindByLookupCompatibleLocationSet(initial, ls)) { + LocationSet_Term(newLS); + LocationSet_InitKnown(newLS, LocationSet_block(ls), cint64_zero, 0, LocationSet_rtype(ls)); + if (!PointsToFunction_FindByLookupCompatibleLocationSet(initial, newLS)) { + LocationSet *newLS2; + LocationSetSet *newSet; + PointsToEntry *newPTE; + + newLS2 = LocationSet_New(); + LocationSet_InitKnown(newLS2, block, cint64_zero, 0, LocationSet_rtype(ls)); + + newSet = LocationSetSet_New(); + LocationSetSet_Init(newSet); + LocationSetSet_Add(newSet, newLS2); + + newPTE = PointsToEntry_New(); + PointsToEntry_Init(newPTE, newLS, newSet); + result |= PointsToFunction_Add(initial, newPTE); + PointsToEntry_Term(newPTE); + PointsToEntry_Delete(newPTE); + + LocationSetSet_Term(newSet); + LocationSetSet_Delete(newSet); + + LocationSet_Term(newLS2); + LocationSet_Delete(newLS2); + } + } + } + } + + LocationSet_Term(newLS); + LocationSet_Delete(newLS); + } + + return result; +} + +static Boolean GetActualLocsOfExtendedParam(LocationSetSet *set, LocationSet *ls, Object *var, Stack **stackPtr, ParamMappingFunction *map, Boolean flag) { + Boolean result; + PAMemoryBlock *block; + IROLinear *nd; + ExtendedParam *ep; + ParamMapping *mapping; + Type *savedRtype; + CInt64 savedField; + UInt32 savedStride; + LocationSetSet *newSet; + + IRO_ASSERT(2821, set == NULL || set != NULL); + IRO_ASSERT(2822, (ls != NULL && var == NULL) || (ls == NULL && var != NULL)); + IRO_ASSERT(2823, ls == NULL || !LocationSet_IsUnknown(ls)); + IRO_ASSERT(2824, var != &stUnknown); + IRO_ASSERT(2825, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL); + IRO_ASSERT(2826, map == NULL || map != NULL); + + result = 0; + block = NULL; + nd = 0; + ep = NULL; + mapping = NULL; + + if (ls) { + block = LocationSet_block(ls); + IRO_ASSERT(2838, block != NULL); + IRO_ASSERT(2839, PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM); + + ep = PAMemoryBlock_thing(block); + IRO_ASSERT(2842, ep != NULL); + + savedField = LocationSet_field(ls); + savedStride = LocationSet_stride(ls); + savedRtype = LocationSet_rtype(ls); + } + + IRO_ASSERT(2848, ep == NULL || ep != NULL); + + if (stackPtr && *stackPtr) { + StackElement *element = Stack_Top(stackPtr); + if (element && !map) + map = StackElement_map(element); + } + + IRO_ASSERT(2859, map == NULL || map != NULL); + + if (ep) { + IRO_ASSERT(2863, var == NULL); + ObjectSet_ForEach(ExtendedParam_objectSet(ep), FindGlobalObjectAction, &var); + if (!var) + var = ObjectSet_FindFirst(ExtendedParam_objectSet(ep)); + if (!var) + var = &stUnknown; + } + + IRO_ASSERT(2870, var != NULL); + + if (map && var != &stUnknown) { + if (flag) + result |= FillInAppropriateMappingsWithExtParam(map, var, ep, NULL); + mapping = ParamMappingFunction_FindMappingByFormal(map, var); + } + + newSet = LocationSetSet_New(); + LocationSetSet_Init(newSet); + + IRO_ASSERT(2884, mapping == NULL || mapping != NULL); + + if (mapping) + nd = ParamMapping_actual(mapping); + + if (!nd) { + if (!ls) { + IRO_ASSERT(2893, var != NULL); + IRO_ASSERT(2894, ep == NULL); + + if (var != &stUnknown) { + ep = CreateExtendedParam(stackPtr, NULL, var, &result); + if (flag && mapping && ParamMapping_extended(mapping) != ep) { + ParamMapping_SetExtended(mapping, ep); + result = 1; + } + + block = PAMemoryBlock_New(); + PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_EXTENDEDPARAM, ep); + savedField = cint64_zero; + savedStride = 0; + savedRtype = CDecl_NewPointerType(var->type); + } else { + block = LocationSet_block(stUnknownLs); + savedRtype = NULL; + } + } else if (var == &stUnknown || !ObjectIsAnExtendedParamCandidate(var)) { + block = LocationSet_block(stUnknownLs); + savedRtype = NULL; + } + + IRO_ASSERT(2925, block != NULL); + + if (block == LocationSet_block(stUnknownLs)) { + LocationSetSet_AddUnknown(newSet, savedRtype, NULL, NULL); + } else { + LocationSet *tmp = LocationSet_New(); + LocationSet_InitKnown(tmp, block, savedField, savedStride, savedRtype); + LocationSetSet_Add(newSet, tmp); + LocationSet_Term(tmp); + LocationSet_Delete(tmp); + } + } else { + Stack *next; + StackElement *element; + if (stackPtr && *stackPtr && (next = Stack_Next(stackPtr)) && (element = Stack_Top(&next))) { + if (ls) { + if (!savedStride && !CInt64_IsZero(&savedField)) { + IROLinear *ic; + IROLinear *d; + ic = IRO_NewIntConst(savedField, TYPE(&stunsignedlong)); + d = IRO_NewLinear(IROLinearOp2Arg); + d->index = ++IRO_NumLinear; + d->rtype = nd->rtype; + d->u.diadic.left = nd; + d->u.diadic.right = ic; + nd = d; + } + if (savedStride) { + IROLinear *call; + IROLinear *d; + call = IRO_NewLinear(IROLinearFunccall); + call->u.funccall.returnedLocs = LocationSetSet_New(); + LocationSetSet_Init(call->u.funccall.returnedLocs); + LocationSetSet_AddUnknown(call->u.funccall.returnedLocs, NULL, NULL, NULL); + d = IRO_NewLinear(IROLinearOp2Arg); + d->index = ++IRO_NumLinear; + d->rtype = nd->rtype; + d->u.diadic.left = nd; + d->u.diadic.right = call; + nd = d; + } + } + EvalExpr(newSet, StackElement_proc(element), nd, &next, StackElement_map(element), StackElement_ptf(element)); + } else { + LocationSetSet_AddUnknown(newSet, NULL, NULL, NULL); + } + } + + if (set) + LocationSetSet_AddSet(set, newSet); + + LocationSetSet_Term(newSet); + LocationSetSet_Delete(newSet); + + return result; +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct ExpandLocationSetSetActionParams { + LocationSetSet *toBeRemoved; + LocationSetSet *toBeAdded; + Stack **stackPtr; + ParamMappingFunction *map; + Boolean x10; +} ExpandLocationSetSetActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void ExpandLocationSetSetToActualsAction(LocationSet *ls, void *refcon) { + ExpandLocationSetSetActionParams *params; + + IRO_ASSERT(3021, ls != NULL); + IRO_ASSERT(3022, refcon != NULL); + + params = refcon; + + IRO_ASSERT(3026, params->toBeRemoved != NULL); + IRO_ASSERT(3027, params->toBeAdded != NULL); + IRO_ASSERT(3028, params->stackPtr == NULL || *params->stackPtr == NULL || *params->stackPtr != NULL); + IRO_ASSERT(3029, params->map == NULL || params->map != NULL); + + if (!LocationSet_IsUnknown(ls)) { + PAMemoryBlock *block = LocationSet_block(ls); + if (block && PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) { + ExtendedParam *ep = PAMemoryBlock_thing(block); + if (ep) { + ObjectSet *objSet = ExtendedParam_objectSet(ep); + Object *obj = NULL; + ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj); + if (!obj) { + LocationSetSet_Add(params->toBeRemoved, ls); + params->x10 |= GetActualLocsOfExtendedParam(params->toBeAdded, ls, NULL, params->stackPtr, params->map, 0); + } + } + } + } +} + +static int ExpandLocationSetSetToActuals(Stack **stackPtr, ParamMappingFunction *map, LocationSetSet *thingsPointedTo) { + LocationSetSet *toBeRemoved; + LocationSetSet *toBeAdded; + ExpandLocationSetSetActionParams params; + Boolean result; + + IRO_ASSERT(3063, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL); + IRO_ASSERT(3064, map == NULL || map != NULL); + IRO_ASSERT(3065, thingsPointedTo != NULL); + + toBeRemoved = LocationSetSet_New(); + LocationSetSet_Init(toBeRemoved); + + toBeAdded = LocationSetSet_New(); + LocationSetSet_Init(toBeAdded); + + memset(¶ms, 0, sizeof(params)); + params.toBeRemoved = toBeRemoved; + params.toBeAdded = toBeAdded; + params.stackPtr = stackPtr; + params.map = map; + params.x10 = 0; + + LocationSetSet_ForEach(thingsPointedTo, ExpandLocationSetSetToActualsAction, ¶ms); + + result = params.x10; + LocationSetSet_sub_488700(thingsPointedTo, toBeRemoved); + LocationSetSet_AddSet(thingsPointedTo, toBeAdded); + + LocationSetSet_Term(toBeRemoved); + LocationSetSet_Delete(toBeRemoved); + + LocationSetSet_Term(toBeAdded); + LocationSetSet_Delete(toBeAdded); + + return result; +} + +static void EvaluatePartialAbsolute(LocationSetSet *set, LocationSetSet *thingsPointedTo, LocationSet *dst, Type *indRtype) { + LocationSet *absLoc; + Type *absLocRtype; + PAMemoryBlock *block; + + IRO_ASSERT(3108, set != NULL); + IRO_ASSERT(3109, thingsPointedTo != NULL); + IRO_ASSERT(3110, dst != NULL); + IRO_ASSERT(3111, indRtype != NULL); + + absLoc = LocationSetSet_FindFirst(thingsPointedTo); + IRO_ASSERT(3114, absLoc != NULL); + + if (!LocationSet_IsUnknown(absLoc)) + absLocRtype = LocationSet_rtype(absLoc); + + if (!LocationSet_IsUnknown(absLoc) && indRtype->size == absLocRtype->size) { + LocationSetSet_AddSet(set, thingsPointedTo); + } else if ( + !LocationSet_IsUnknown(absLoc) && + !LocationSet_stride(absLoc) && + LocationSetSet_Count(thingsPointedTo) == 1 && + (block = LocationSet_block(absLoc)) && + PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_INT && + absLocRtype->size <= stsignedlonglong.size && + indRtype->size < absLocRtype->size + ) { + CInt64 val2; + CInt64 val8; + CInt64 val4; + CInt64 val5; + CInt64 val1; + CInt64 val3; + CInt64 val7; + CInt64 val6; + LocationSet *ls; + + val1 = LocationSet_field(absLoc); + val2 = *((CInt64 *) PAMemoryBlock_thing(block)); + CInt64_SetLong(&val3, 8); + val4 = cint64_zero; + CInt64_SetLong(&val5, stsignedlonglong.size - absLocRtype->size); + val6 = CInt64_Sub(LocationSet_field(dst), val1); + CInt64_SetLong(&val7, absLocRtype->size - indRtype->size); + val5 = CInt64_Add(val5, val6); + val4 = CInt64_Add(val4, val7); + val4 = CInt64_Sub(val4, val6); + val5 = CInt64_MulU(val5, val3); + val4 = CInt64_MulU(val4, val3); + val8 = cint64_negone; + val8 = CInt64_Shl(val8, val5); + val8 = CInt64_ShrU(val8, val5); + val2 = CInt64_And(val2, val8); + val2 = CInt64_ShrU(val2, val4); + + block = PAMemoryBlock_New(); + PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_INT, &val2); + + ls = LocationSet_New(); + LocationSet_InitKnown(ls, block, cint64_zero, 0, indRtype); + LocationSetSet_Add(set, ls); + LocationSet_Term(ls); + LocationSet_Delete(ls); + } else { + LocationSetSet_AddUnknown(set, indRtype, NULL, NULL); + } +} + +static Boolean AddToInitialPointsToFunc(Boolean flag, PartialTransferFunction *ptf, LocationSet *dst, LocationSetSet *set) { + Boolean result; + LocationSet *ls; + PointsToFunction *initial; + PointsToEntry *pte; + + IRO_ASSERT(3192, ptf == NULL || ptf != NULL); + IRO_ASSERT(3193, dst != NULL); + IRO_ASSERT(3194, set != NULL); + + result = 0; + + if (flag && ptf) { + ls = LocationSetSet_FindUnknown(set); + if (!ls || LocationSet_rtype(ls)) { + initial = PartialTransferFunction_initialPointsToFn(ptf); + if (initial && !PointsToFunction_FindByLookupCompatibleLocationSet(initial, dst)) { + IRO_ASSERT(3208, dst != NULL); + + pte = PointsToEntry_New(); + PointsToEntry_Init(pte, dst, set); + result = PointsToFunction_AddWithoutChecking(initial, pte); + PointsToEntry_Term(pte); + PointsToEntry_Delete(pte); + } + } + } + + return result; +} + +static Boolean Lookup(LocationSetSet *set, Stack **stackPtr, Object *proc, ParamMappingFunction *map, PartialTransferFunction *ptf, LocationSet *dst, PointsToFunction *pointsToFunc, Boolean unk, Type *indRtype) { + Boolean result; + LocationSetSet *mySet; + LocationSetSet *set2; + PAMemoryBlock *block; + ExtendedParam *ep; + PALocalVar *local; + ObjectSet *objSet; + Object *obj; + + IRO_ASSERT(3245, set == NULL || set != NULL); + IRO_ASSERT(3246, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL); + IRO_ASSERT(3247, proc == NULL || proc != NULL); + IRO_ASSERT(3248, map == NULL || map != NULL); + IRO_ASSERT(3249, ptf == NULL || ptf != NULL); + IRO_ASSERT(3250, dst != NULL); + IRO_ASSERT(3251, pointsToFunc == NULL || pointsToFunc != NULL); + IRO_ASSERT(3252, indRtype == NULL || indRtype != NULL); + + result = 0; + + set2 = NULL; + + mySet = LocationSetSet_New(); + LocationSetSet_Init(mySet); + + if (proc) { + if (LocationIsVolatile(dst, proc)) + LocationSetSet_AddUnknown(mySet, indRtype, NULL, NULL); + } + + if (pointsToFunc && !LocationSet_IsUnknown(dst)) { + PointsToEntry *pte = PointsToFunction_FindByLookupCompatibleLocationSet(pointsToFunc, dst); + if (pte) { + set2 = PointsToEntry_locs(pte); + } else if (indRtype) { + pte = PointsToFunction_FindContainingLocationSet(pointsToFunc, dst, indRtype); + if (pte) + set2 = PointsToEntry_locs(pte); + } + } + + if (set2) { + if (indRtype) + EvaluatePartialAbsolute(mySet, set2, dst, indRtype); + else + LocationSetSet_AddSet(mySet, set2); + } else if (!set2) { + block = NULL; + if (!LocationSet_IsUnknown(dst)) + block = LocationSet_block(dst); + + if (!LocationSet_IsUnknown(dst) && LocationSet_stride(dst)) { + LocationSetSet_AddUnknown(mySet, indRtype, NULL, NULL); + } else if ( + block && + PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM && + (ep = PAMemoryBlock_thing(block)) && + (objSet = ExtendedParam_objectSet(ep)) + ) { + obj = NULL; + ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj); + if (!obj) { + LocationSetSet *lss3; + LocationSet *tmp; + // Boolean result1; + EvalExprAction3Params params; + + lss3 = LocationSetSet_New(); + LocationSetSet_Init(lss3); + result = GetActualLocsOfExtendedParam(lss3, dst, NULL, stackPtr, map, unk); + + memset(¶ms, 0, sizeof(params)); + params.set = mySet; + params.stackPtr = stackPtr; + params.proc = proc; + params.map = map; + params.ptf = ptf; + params.pointsToFunc = pointsToFunc; + params.indRtype = indRtype; + params.x1C = 0; + LocationSetSet_ForEach(lss3, EvalExprAction3, ¶ms); + result |= params.x1C; + + LocationSetSet_Term(lss3); + LocationSetSet_Delete(lss3); + + if ((tmp = LocationSetSet_FindUnknown(mySet))) { + if (!LocationSet_restriction(tmp) && ObjectSet_Count(objSet) == 1) { + if ((obj = ObjectSet_FindFirst(objSet))) { + if (ObjectIsRestrictQualified(obj)) { + LocationSet_Term(tmp); + LocationSet_InitUnknown(tmp, indRtype, block, NULL); + } + } + } + } + + result |= AddToInitialPointsToFunc(unk, ptf, dst, mySet); + } else { + // Boolean result1; + Stack *next; + StackElement *element; + + result = GetActualLocsOfExtendedParam(NULL, dst, NULL, stackPtr, map, unk); + if (stackPtr && *stackPtr && (next = Stack_Next(stackPtr)) && (element = Stack_Top(&next))) { + result |= Lookup(mySet, &next, StackElement_proc(element), StackElement_map(element), + StackElement_ptf(element), dst, StackElement_funcCall(element)->pointsToFunction, unk, indRtype); + } else { + LocationSetSet_AddUnknown(mySet, indRtype, NULL, NULL); + } + + result |= AddToInitialPointsToFunc(unk, ptf, dst, mySet); + } + } else if ( + block && + PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_LOCALVAR && + (local = PAMemoryBlock_thing(block)) && + proc && + (obj = GetLocalObject(local, proc, 1)) && + ObjectIsAFunctionArgument(proc, obj) + ) { + result = LookupParam(mySet, dst, obj, stackPtr, proc, map, ptf, unk); + } else { + LocationSetSet_AddUnknown(mySet, indRtype, NULL, NULL); + } + } + + if (set) + LocationSetSet_AddSet(set, mySet); + + LocationSetSet_Term(mySet); + LocationSetSet_Delete(mySet); + + return result; +} + +static Boolean InputsHaveNewPointerValues(PartialTransferFunction *tgtPTF, PartialTransferFunction *ptf) { + IRO_ASSERT(3393, tgtPTF != NULL); + IRO_ASSERT(3394, ptf != NULL); + + return 0; +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct CreateEPActionParams { + ParamMapping *last; + ParamMapping *lowest; +} CreateEPActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void CreateExtendedParamAction(ParamMapping *mapping, void *refcon) { + CreateEPActionParams *params; + ExtendedParam *ep; + uint32 value; + ExtendedParam *lowestEP; + uint32 lowestValue; + ExtendedParam *lastEP; + uint32 lastValue; + + IRO_ASSERT(3417, mapping != NULL); + IRO_ASSERT(3418, refcon != NULL); + + params = refcon; + + IRO_ASSERT(3422, params->last == NULL || params->last != NULL); + IRO_ASSERT(3423, params->lowest == NULL || params->lowest != NULL); + + if ((ep = ParamMapping_extended(mapping))) { + value = ExtendedParam_sub_489110(ep); + + if (params->lowest) { + lowestEP = ParamMapping_extended(params->lowest); + lowestValue = ExtendedParam_sub_489110(lowestEP); + if (params->last) { + lastEP = ParamMapping_extended(params->last); + lastValue = ExtendedParam_sub_489110(lastEP); + if (value > lastValue && value < lowestValue) + params->lowest = mapping; + } else if (value < lowestValue) { + params->lowest = mapping; + } + } else if (params->last) { + lastEP = ParamMapping_extended(params->last); + lastValue = ExtendedParam_sub_489110(lastEP); + if (value > lastValue) + params->lowest = mapping; + } else { + params->lowest = mapping; + } + } +} + +static ExtendedParam *FindMatchingExtendedParam(Stack **stackPtr, ParamMappingFunction *map, LocationSetSet *lss, ParamMapping *lowest, Boolean *result) { + ExtendedParam *ep; + ExtendedParam *lowestEP; + + IRO_ASSERT(3473, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL); + IRO_ASSERT(3474, map == NULL || map != NULL); + IRO_ASSERT(3475, lss != NULL); + IRO_ASSERT(3476, lowest != NULL); + + ep = NULL; + if ((lowestEP = ParamMapping_extended(lowest))) { + PAMemoryBlock *block; + LocationSet *lowestLS; + LocationSetSet *lowestLSS; + + block = PAMemoryBlock_New(); + PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_EXTENDEDPARAM, lowestEP); + + lowestLS = LocationSet_New(); + LocationSet_InitKnown(lowestLS, block, cint64_zero, 0, TYPE(&void_ptr)); + + lowestLSS = LocationSetSet_New(); + LocationSetSet_Init(lowestLSS); + + *result |= GetActualLocsOfExtendedParam(lowestLSS, lowestLS, NULL, stackPtr, map, 0); + if (LocationSetSets_Equal(lowestLSS, lss)) + ep = lowestEP; + + LocationSetSet_Term(lowestLSS); + LocationSetSet_Delete(lowestLSS); + + LocationSet_Term(lowestLS); + LocationSet_Delete(lowestLS); + } + + return ep; +} + +static ExtendedParam *CreateExtendedParam(Stack **stackPtr, ParamMappingFunction *map, Object *var, Boolean *result) { + ExtendedParam *ep; + ParamMapping *mapping; + LocationSetSet *lss; + CreateEPActionParams params; + + IRO_ASSERT(3518, map == NULL || map != NULL); + IRO_ASSERT(3519, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL); + IRO_ASSERT(3520, var != NULL); + + mapping = NULL; + if (map) + mapping = ParamMappingFunction_FindMappingByFormal(map, var); + + ep = ExtendedParam_FindByObject(var); + if (ep) { + if (mapping) + IRO_ASSERT(3535, ep == ParamMapping_extended(mapping) || ParamMapping_extended(mapping) == NULL); + } else if (map && !ObjectIsRestrictQualified(var)) { + lss = LocationSetSet_New(); + LocationSetSet_Init(lss); + *result |= GetActualLocsOfExtendedParam(lss, NULL, var, stackPtr, map, 0); + + memset(¶ms, 0, sizeof(params)); + params.last = NULL; + do { + params.lowest = NULL; + pmf_sub_487C70(map, CreateExtendedParamAction, ¶ms); + if (params.lowest && params.lowest != mapping) + ep = FindMatchingExtendedParam(stackPtr, map, lss, params.lowest, result); + params.last = params.lowest; + } while (params.lowest && !ep); + + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + } + + if (!ep) + ep = ExtendedParam_FindByObject(var); + + if (!ep) { + ep = ExtendedParam_New(); + ExtendedParam_Init(ep, var); + } else { + ExtendedParam_sub_4867B0(ep, var); + } + + if (stExtParamSet) + ExtParamSet_sub_487630(stExtParamSet, ep); + + IRO_ASSERT(3583, ep != NULL); + + return ep; +} + +#ifdef IRO_DEBUG +void __assertion_failed(char *expr, char *filename, int line) { + CError_ASSERT(3605, filename); + CError_Internal(filename, line); +} +#endif + +static void RecordActuals(IROLinear *nd, Object *proc, ParamMappingFunction *map) { + IRO_ASSERT(3628, nd != NULL); + IRO_ASSERT(3629, nd->type == IROLinearFunccall); + IRO_ASSERT(3630, proc != NULL); + IRO_ASSERT(3631, map != NULL); + + if (proc != &stUnknown) { + int i; + ObjectList *args; + Object *arg; + + args = FunctionArguments(proc); + if (args) + arg = args->object; + else + arg = &stUnknown; + + for (i = 0; i < nd->u.funccall.argCount; i++) { + IRO_ASSERT(3643, arg != NULL); + + if (arg != &stUnknown) { + ParamMapping *mapping = ParamMapping_New(); + ParamMapping_Init_PROBABLY(mapping, nd->u.funccall.args[i], arg, NULL); + Pmf_Add_sub_486610(map, mapping); + ParamMapping_Term(mapping); + ParamMapping_Delete(mapping); + } + + if (args) { + args = args->next; + if (args) + arg = args->object; + else + arg = &stUnknown; + } + } + } +} + +static Boolean IsAddressableLocation(LocationSet *loc, Object *proc, IRONode *fnode, IROLinear *nd) { + IRO_ASSERT(3676, loc != NULL); + IRO_ASSERT(3677, fnode != NULL); + IRO_ASSERT(3678, nd != NULL); + + if (!LocationSet_IsUnknown(loc)) { + PAMemoryBlock *block; + PALocalVar *local; + Object *obj; + ExtendedParam *ep; + ObjectSet *objSet; + + block = LocationSet_block(loc); + if ( + PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_LOCALVAR && + (local = PAMemoryBlock_thing(block)) && + (obj = GetLocalObject(local, proc, 0)) && + fnode->addressed && + !ObjectSet_sub_485020(fnode->addressed, obj) + ) { + return 0; + } + + if ( + PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM && + (ep = PAMemoryBlock_thing(block)) && + (objSet = ExtendedParam_objectSet(ep)) && + ObjectSet_Count(objSet) == 1 && + (obj = ObjectSet_FindFirst(objSet)) && + ObjectIsAFunctionArgument(proc, obj) && + ObjectIsRestrictQualified(obj) + ) { + return 0; + } + } + + return 1; +} + +static Boolean LocationSetsAlias(LocationSet *ls1, LocationSet *ls2) { + IRO_ASSERT(3719, ls1 != NULL); + IRO_ASSERT(3720, ls2 != NULL); + + return + (ls1 == ls2) || + LocationSet_IsUnknown(ls1) || + LocationSet_IsUnknown(ls2) || + ( + (LocationSet_stride(ls1) || + LocationSet_stride(ls2) || + CInt64_Equal(LocationSet_field(ls1), LocationSet_field(ls2))) && + MemoryBlocks_Equal(LocationSet_block(ls1), LocationSet_block(ls2)) + ); +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct FindAliasingParams { + LocationSetSet *x0; + LocationSet *x4; + Boolean x8; +} FindAliasingParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void FindAliasingAction2(LocationSet *ls, void *refcon) { + FindAliasingParams *params; + + params = refcon; + + if (!params->x8) { + if (LocationSetsAlias(params->x4, ls)) + params->x8 = 1; + } +} + +static void FindAliasingAction(LocationSet *ls, void *refcon) { + FindAliasingParams *params; + + IRO_ASSERT(3751, ls != NULL); + IRO_ASSERT(3752, refcon != NULL); + + params = refcon; + + if (!params->x8) { + params->x4 = ls; + LocationSetSet_ForEach(params->x0, FindAliasingAction2, params); + } +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct KillLocationParams { + Object *proc; + IRONode *fnode; + IROLinear *nd; + PartialTransferFunction *ptf; + PointsToFunction *toBeKilled; + LocationSet *dst; + Boolean x18; +} KillLocationParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void KillAllAddressableLocationsAction(PointsToEntry *pte, void *refcon) { + KillLocationParams *params; + LocationSet *loc; + + IRO_ASSERT(3779, pte != NULL); + IRO_ASSERT(3780, refcon != NULL); + + params = refcon; + + IRO_ASSERT(3784, params->proc != NULL); + IRO_ASSERT(3785, params->fnode != NULL); + IRO_ASSERT(3786, params->nd != NULL); + IRO_ASSERT(3787, params->ptf != NULL); + IRO_ASSERT(3788, params->toBeKilled != NULL); + IRO_ASSERT(3789, params->dst == NULL); + + loc = PointsToEntry_loc(pte); + IRO_ASSERT(3793, loc != NULL); + IRO_ASSERT(3794, !LocationSet_IsUnknown(loc)); + + if (IsAddressableLocation(loc, params->proc, params->fnode, params->nd)) + PointsToFunction_Add(params->toBeKilled, pte); +} + +static void KillAllAliasingExtParamLocsAction(PointsToEntry *pte, void *refcon) { + KillLocationParams *params; + LocationSet *loc; + + IRO_ASSERT(3813, pte != NULL); + IRO_ASSERT(3814, refcon != NULL); + + params = refcon; + + IRO_ASSERT(3818, params->proc != NULL); + IRO_ASSERT(3819, params->fnode != NULL); + IRO_ASSERT(3820, params->nd != NULL); + IRO_ASSERT(3821, params->ptf != NULL); + IRO_ASSERT(3822, params->toBeKilled != NULL); + IRO_ASSERT(3823, params->dst != NULL); + IRO_ASSERT(3824, LocationSet_block(params->dst) != NULL); + IRO_ASSERT(3825, PAMemoryBlock_kind(LocationSet_block(params->dst)) == PAMEMORYBLOCKKIND_EXTENDEDPARAM); + + loc = PointsToEntry_loc(pte); + IRO_ASSERT(3829, loc != NULL); + IRO_ASSERT(3830, !LocationSet_IsUnknown(loc)); + + if (loc != params->dst) { + if (LocationSetsAlias(loc, params->dst)) { + PointsToFunction_Add(params->toBeKilled, pte); + } else { + ExtendedParam *ep; + ObjectSet *objSet; + Object *obj; + PAMemoryBlock *block; + + if ( + (ep = PAMemoryBlock_thing(LocationSet_block(params->dst))) && + (objSet = ExtendedParam_objectSet(ep)) && + (ObjectSet_Count(objSet) != 1 || !(obj = ObjectSet_FindFirst(objSet)) || !ObjectIsRestrictQualified(obj)) && + (block = LocationSet_block(loc)) && + PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM && + (ep = PAMemoryBlock_thing(block)) && + (objSet = ExtendedParam_objectSet(ep)) && + (ObjectSet_Count(objSet) != 1 || !(obj = ObjectSet_FindFirst(objSet)) || !ObjectIsRestrictQualified(obj)) + ) { + LocationSetSet *lss1; + LocationSetSet *lss2; + Boolean changed; + FindAliasingParams aparams; + + lss1 = LocationSetSet_New(); + LocationSetSet_Init(lss1); + lss2 = LocationSetSet_New(); + LocationSetSet_Init(lss2); + + changed = GetActualLocsOfExtendedParam(lss1, loc, NULL, &stCallingContextStack, NULL, 0); + changed |= GetActualLocsOfExtendedParam(lss2, params->dst, NULL, &stCallingContextStack, NULL, 0); + + memset(&aparams, 0, sizeof(aparams)); + aparams.x8 = 0; + aparams.x0 = lss2; + LocationSetSet_ForEach(lss1, FindAliasingAction, &aparams); + if (aparams.x8) + PointsToFunction_Add(params->toBeKilled, pte); + + LocationSetSet_Term(lss1); + LocationSetSet_Delete(lss1); + LocationSetSet_Term(lss2); + LocationSetSet_Delete(lss2); + } + } + } +} + +static void KillLocationsAction(PointsToEntry *pte, void *refcon) { + KillLocationParams *params; + LocationSet *loc; + LocationSetSet *lss; + + IRO_ASSERT(3886, pte != NULL); + IRO_ASSERT(3887, refcon != NULL); + + params = refcon; + + IRO_ASSERT(3891, params->proc != NULL); + IRO_ASSERT(3892, params->fnode != NULL); + IRO_ASSERT(3893, params->nd != NULL); + IRO_ASSERT(3894, params->ptf != NULL); + IRO_ASSERT(3895, params->toBeKilled != NULL); + IRO_ASSERT(3896, params->dst == NULL); + + loc = PointsToEntry_loc(pte); + IRO_ASSERT(3900, loc != NULL); + IRO_ASSERT(3901, !LocationSet_IsUnknown(loc)); + + lss = LocationSetSet_New(); + LocationSetSet_Init(lss); + LocationSetSet_AddUnknown(lss, NULL, NULL, NULL); + + params->x18 |= Assign(params->ptf, loc, lss, params->proc, params->nd, params->fnode); + + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); +} + +static Boolean KillAllAddressableLocations(Object *proc, IRONode *fnode, IROLinear *nd, PartialTransferFunction *ptf) { + Boolean result; + PointsToFunction *pointsToFunc; + PointsToFunction *pointsToFuncCopy; + PointsToFunction *toBeKilled; + KillLocationParams params; + + IRO_ASSERT(3921, proc != NULL); + IRO_ASSERT(3922, fnode == NULL || fnode != NULL); + IRO_ASSERT(3923, nd == NULL || nd != NULL); + IRO_ASSERT(3924, ptf != NULL); + + if (nd && nd->pointsToFunction) + pointsToFunc = nd->pointsToFunction; + else + pointsToFunc = PartialTransferFunction_finalPointsToFn(ptf); + + pointsToFuncCopy = PointsToFunction_New(); + PointsToFunction_Copy(pointsToFuncCopy, pointsToFunc); + + toBeKilled = PointsToFunction_New(); + PointsToFunction_Init(toBeKilled); + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.fnode = fnode; + params.nd = nd; + params.ptf = ptf; + params.toBeKilled = toBeKilled; + params.dst = NULL; + params.x18 = 0; + + if (pointsToFunc) { + PointsToFunction_ForEach(pointsToFunc, KillAllAddressableLocationsAction, ¶ms); + PointsToFunction_ForEach(params.toBeKilled, KillLocationsAction, ¶ms); + } + + PointsToFunction_Term(toBeKilled); + PointsToFunction_Delete(toBeKilled); + + if (params.x18) + result = !PointsToFunctions_Equal(pointsToFuncCopy, pointsToFunc); + else + result = 0; + + PointsToFunction_Term(pointsToFuncCopy); + PointsToFunction_Delete(pointsToFuncCopy); + + return result; +} + +static void KillAllAliasingExtParamLocs(Object *proc, IRONode *fnode, IROLinear *nd, PartialTransferFunction *ptf, LocationSet *dst) { + PointsToFunction *pointsToFunc; + PointsToFunction *toBeKilled; + KillLocationParams params; + + IRO_ASSERT(3974, proc != NULL); + IRO_ASSERT(3975, fnode == NULL || fnode != NULL); + IRO_ASSERT(3976, nd == NULL || nd != NULL); + IRO_ASSERT(3977, ptf != NULL); + IRO_ASSERT(3978, dst != NULL); + + if (!LocationSet_IsUnknown(dst) && LocationSet_block(dst)) { + if (PAMemoryBlock_kind(LocationSet_block(dst)) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) { + + if (nd && nd->pointsToFunction) + pointsToFunc = nd->pointsToFunction; + else + pointsToFunc = PartialTransferFunction_finalPointsToFn(ptf); + + toBeKilled = PointsToFunction_New(); + PointsToFunction_Init(toBeKilled); + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.fnode = fnode; + params.nd = nd; + params.ptf = ptf; + params.toBeKilled = toBeKilled; + params.dst = dst; + params.x18 = 0; + + if (pointsToFunc) { + PointsToFunction_ForEach(pointsToFunc, KillAllAliasingExtParamLocsAction, ¶ms); + PointsToFunction_ForEach(params.toBeKilled, KillLocationsAction, ¶ms); + } + + PointsToFunction_Term(toBeKilled); + PointsToFunction_Delete(toBeKilled); + } + } +} + +static Boolean Assign(PartialTransferFunction *ptf, LocationSet *dst, LocationSetSet *srcs, Object *proc, IROLinear *nd, IRONode *fnode) { + PointsToFunction *pointsToFunc; + Boolean result; + PointsToEntry *pte; + LocationSet *loc; + LocationSetSet *locs; + LocationSet *bitfieldOf; + LocationSetSet *lss; + + IRO_ASSERT(4027, ptf != NULL); + IRO_ASSERT(4028, dst != NULL); + IRO_ASSERT(4029, srcs != NULL); + IRO_ASSERT(4030, proc != NULL); + IRO_ASSERT(4031, nd == NULL || nd != NULL); + IRO_ASSERT(4032, fnode == NULL || fnode != NULL); + + if (nd) { + if (!nd->pointsToFunction) { + nd->pointsToFunction = PointsToFunction_New(); + PointsToFunction_Init(nd->pointsToFunction); + } + pointsToFunc = nd->pointsToFunction; + } else { + pointsToFunc = PartialTransferFunction_finalPointsToFn(ptf); + } + + pte = PointsToFunction_FindByLookupCompatibleLocationSet(pointsToFunc, dst); + if (pte) { + loc = PointsToEntry_loc(pte); + locs = PointsToEntry_locs(pte); + IRO_ASSERT(4056, !LocationSet_IsUnknown(dst)); + IRO_ASSERT(4057, LocationSet_stride(dst) == 0 || LocationSet_stride(loc) != 0); + + result = !LocationSetSets_Equal(srcs, locs) || LocationSet_stride(dst) != LocationSet_stride(loc); + + if (result) { + pte = PointsToEntry_New(); + PointsToEntry_Init(pte, dst, srcs); + PointsToFunction_RemoveByLocationSet(pointsToFunc, loc); + PointsToFunction_AddWithoutChecking(pointsToFunc, pte); + PointsToEntry_Term(pte); + PointsToEntry_Delete(pte); + } + } else if (!LocationSet_IsUnknown(dst)) { + KillAllAliasingExtParamLocs(proc, fnode, nd, ptf, dst); + + pte = PointsToEntry_New(); + PointsToEntry_Init(pte, dst, srcs); + result = PointsToFunction_AddWithoutChecking(pointsToFunc, pte); + PointsToEntry_Term(pte); + PointsToEntry_Delete(pte); + } else if ((bitfieldOf = LocationSet_bitfieldOf(dst))) { + lss = LocationSetSet_New(); + LocationSetSet_Init(lss); + LocationSetSet_AddUnknown(lss, NULL, NULL, NULL); + result = Assign(ptf, bitfieldOf, lss, proc, nd, fnode); + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + } else if (!LocationSet_restriction(dst)) { + result = KillAllAddressableLocations(proc, fnode, nd, ptf); + } + + return result; +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct EvalMeetActionParams { + Object *proc; + IRONode *fnode; + IRONode *pred; + IROLinear *nd; + PartialTransferFunction *ptf; + Boolean x14; + Boolean x15; +} EvalMeetActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void EvalMeetAction(PointsToEntry *pte, void *refcon) { + EvalMeetActionParams *params; + LocationSet *loc; + LocationSetSet *set; + UInt16 i; + + IRO_ASSERT(4123, pte != NULL); + IRO_ASSERT(4124, refcon != NULL); + + params = refcon; + + IRO_ASSERT(4128, params->proc != NULL); + IRO_ASSERT(4129, params->fnode != NULL); + IRO_ASSERT(4130, params->pred != NULL); + IRO_ASSERT(4131, params->nd != NULL); + IRO_ASSERT(4132, params->ptf != NULL); + + loc = PointsToEntry_loc(pte); + + set = LocationSetSet_New(); + LocationSetSet_Init(set); + LocationSetSet_AddSet(set, PointsToEntry_locs(pte)); + + for (i = 0; i < params->fnode->numpred; i++) { + IRONode *pred = FunctionNodeTable(params->proc)[params->fnode->pred[i]]; + if (pred->x3C && pred != params->pred) { + params->x14 |= Lookup(set, &stCallingContextStack, params->proc, NULL, params->ptf, loc, pred->last->pointsToFunction, 0, NULL); + } + } + + params->x15 |= Assign(params->ptf, loc, set, params->proc, params->nd, params->fnode); + LocationSetSet_Term(set); + LocationSetSet_Delete(set); +} + +static Boolean EvalMeet(Object *proc, IRONode *fnode, IROLinear *nd, PartialTransferFunction *ptf) { + PointsToFunction *pointsToFunc; + EvalMeetActionParams params; + int i; + + IRO_ASSERT(4163, proc != NULL); + IRO_ASSERT(4164, fnode != NULL); + IRO_ASSERT(4165, nd != NULL); + IRO_ASSERT(4166, ptf != NULL); + + pointsToFunc = PointsToFunction_New(); + if (nd->pointsToFunction) + PointsToFunction_Copy(pointsToFunc, nd->pointsToFunction); + else + PointsToFunction_Init(pointsToFunc); + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.fnode = fnode; + params.nd = nd; + params.ptf = ptf; + params.x14 = 0; + params.x15 = 0; + + for (i = 0; i < fnode->numpred; i++) { + IRONode *pred = FunctionNodeTable(proc)[fnode->pred[i]]; + params.pred = pred; + if (pred->x3C && pred->last->pointsToFunction) { + PointsToFunction_ForEach(pred->last->pointsToFunction, EvalMeetAction, ¶ms); + } + } + + if (!params.x14 && params.x15) { + if (nd->pointsToFunction) + params.x14 = !PointsToFunctions_Equal(pointsToFunc, nd->pointsToFunction); + else + params.x14 = PointsToFunction_FindFirst(pointsToFunc) != NULL; + } + + PointsToFunction_Term(pointsToFunc); + PointsToFunction_Delete(pointsToFunc); + + return params.x14; +} + +static PartialTransferFunction *AllocatePTF(Object *proc, IROLinear *nd, PartialTransferFunction *ptf) { + PartialTransferFunction *newPTF; + + IRO_ASSERT(4210, proc != NULL); + IRO_ASSERT(4211, proc->u.func.ptfList != NULL); + IRO_ASSERT(4212, nd == NULL || nd != NULL); + IRO_ASSERT(4213, ptf == NULL || ptf != NULL); + + newPTF = PartialTransferFunction_New(); + PartialTransferFunction_Init(newPTF, nd, ptf); + PTFList_sub_48A050(proc->u.func.ptfList, newPTF); + return newPTF; +} + +static Object *FindMainEntryPoint(Object *function) { + IRO_ASSERT(4229, function != NULL); + + return function; +} + +static ObjectList *FunctionArguments(Object *proc) { + Object *search; + ObjectList *scan; + ObjectList *list; + ObjectList *prev; + ExtendedParam *ep; + char *name; + VarInfo *vi; + Object *obj; + FuncArg *args; + Boolean notFound; + + IRO_ASSERT(4252, proc != NULL); + + if (proc == stCurrentProc) { + for (list = arguments; list; list = list->next) { + if ((obj = list->object) && obj->name && (name = obj->name->name) && name[0]) { + prev = NULL; + for (scan = proc->u.func.argList; scan; scan = scan->next) { + prev = scan; + if ((search = scan->object) && search->name && search->name->name) { + if (!strcmp(name, search->name->name)) + break; + } + } + + if (!scan) + search = NULL; + + notFound = !search; + + if (!search) { + search = IRO_malloc(sizeof(Object)); + ep = NULL; + search->u.var.info = IRO_malloc(sizeof(VarInfo)); + memset(search->u.var.info, 0, sizeof(VarInfo)); + search->u.var.info->func = proc; + } else { + ep = search->extParam; + } + + vi = search->u.var.info; + memcpy(search, obj, sizeof(Object)); + search->extParam = ep; + search->u.var.info = vi; + search->u.var.realObj = obj; + + if (notFound) { + scan = IRO_malloc(sizeof(ObjectList)); + scan->next = NULL; + scan->object = search; + if (!prev) + proc->u.func.argList = scan; + else + prev->next = scan; + } + } + } + } else if (proc->type) { + for (args = TYPE_FUNC(proc->type)->args; args; args = args->next) { + if (args->name && (name = args->name->name) && name[0]) { + prev = NULL; + for (scan = proc->u.func.argList; scan; scan = scan->next) { + prev = scan; + if ((search = scan->object) && search->name && search->name->name) { + if (!strcmp(name, search->name->name)) + break; + } + } + + if (!scan) + search = NULL; + + if (!search) { + search = IRO_malloc(sizeof(Object)); + memset(search, 0, sizeof(Object)); + search->datatype = DLOCAL; + search->extParam = NULL; + search->name = GetHashNameNodeExport(name); + search->type = args->type; + search->qual = args->qual; + search->u.var.info = IRO_malloc(sizeof(VarInfo)); + memset(search->u.var.info, 0, sizeof(VarInfo)); + search->u.var.info->func = proc; + + scan = IRO_malloc(sizeof(ObjectList)); + scan->next = NULL; + scan->object = search; + if (!prev) + proc->u.func.argList = scan; + else + prev->next = scan; + } + } + } + } + + return proc->u.func.argList; +} + +static IRONode **FunctionNodeTable(Object *proc) { + IRO_ASSERT(4383, proc != NULL); + + IRO_ASSERT(4391, proc == stCurrentProc); + + return IRO_NodeTable; +} + +static IRONode *FunctionFirstNode(Object *proc) { + IRO_ASSERT(4401, proc != NULL); + + IRO_ASSERT(4409, proc == stCurrentProc); + + return IRO_FirstNode; +} + +static void UpdatePTFDomain() { + // no idea what this would've done +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct EvalCallActionParams { + Object *proc; + IRONode *fnode; + IROLinear *nd; + PartialTransferFunction *ptf; + ParamMappingFunction *map; + int x14; + Boolean x18; + Boolean x19; + Boolean x1A; +} EvalCallActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void EvalCallAction(Object *proc, void *refcon) { + EvalCallActionParams *params; + ParamMappingFunction *pmf; + PartialTransferFunction *tgtPTF; + Boolean flag; + Boolean flag2; + + IRO_ASSERT(4458, proc != NULL); + IRO_ASSERT(4459, refcon != NULL); + + params = refcon; + + IRO_ASSERT(4463, params->proc != NULL); + IRO_ASSERT(4464, params->fnode != NULL); + IRO_ASSERT(4465, params->nd != NULL); + IRO_ASSERT(4466, params->ptf != NULL); + IRO_ASSERT(4467, params->map == NULL || params->map != NULL); + + if (!params->x18) { + pmf = ParamMappingFunction_New(); + ParamMappingFunction_Init(pmf); + RecordActuals(params->nd, proc, pmf); + + flag = 0; + if (!Stack_sub_48A710(&stCallingContextStack, proc)) { + StackElement *element; + + flag2 = 0; + tgtPTF = GetPTF(pmf, proc, params->nd, params->ptf, &flag2); + + element = StackElement_New(); + StackElement_Init(element, proc, tgtPTF, pmf, params->nd); + Stack_sub_48A660(&stCallingContextStack, element); + StackElement_Term(element); + StackElement_Delete(element); + + IRO_ASSERT(4490, tgtPTF != NULL); + + flag = 1; + + if (stPTFList) + PTFList_sub_48A050(stPTFList, tgtPTF); + PartialTransferFunction_sub_48A610(tgtPTF, 0); + + if (flag2 || params->x1A) { + if (params->x1A) { + params->x1A = 0; + EvalProc(proc, pmf, tgtPTF); + } else { + tgtPTF = stUnknownPTF; + } + } + } else { + tgtPTF = stUnknownPTF; + } + + if (params->map) + params->x19 |= ApplySummary(tgtPTF, pmf, params->proc, params->fnode, params->nd, params->ptf, params->map, params->x14 == 1); + + if (flag) { + StackElement *element = Stack_sub_48A5B0(&stCallingContextStack); + StackElement_Term(element); + StackElement_Delete(element); + } + + ParamMappingFunction_Term(pmf); + ParamMappingFunction_Delete(pmf); + } +} + +static Boolean EvalCall(Object *proc, IRONode *fnode, IROLinear *nd, ParamMappingFunction *map, PartialTransferFunction *ptf) { + EvalCallActionParams params; + ObjectSet *objSet; + + IRO_ASSERT(4548, proc != NULL); + IRO_ASSERT(4549, fnode != NULL); + IRO_ASSERT(4550, nd != NULL); + IRO_ASSERT(4551, map != NULL); + IRO_ASSERT(4552, ptf != NULL); + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.fnode = fnode; + params.nd = nd; + params.ptf = ptf; + params.map = map; + params.x18 = 0; + params.x19 = 0; + params.x1A = 0; + + objSet = ObjectSet_New(); + ObjectSet_Init(objSet); + + params.x19 |= FindCallTargets(objSet, proc, nd, map, ptf); + params.x14 = ObjectSet_Count(objSet); + ObjectSet_ForEach(objSet, EvalCallAction, ¶ms); + + ObjectSet_Term(objSet); + ObjectSet_Delete(objSet); + + return params.x19; +} + +static void AdjustTypesForVolatilityAction(LocationSet *ls, void *refcon) { + Type *type; + Type *newtype; + UInt32 qual; + + type = LocationSet_rtype(ls); + switch (type->type) { + case TYPEARRAY: + qual = TYPE_POINTER(type)->qual; + break; + case TYPEPOINTER: + qual = TYPE_POINTER(type)->qual; + break; + case TYPEMEMBERPOINTER: + qual = TYPE_MEMBER_POINTER(type)->qual; + break; + default: + CError_FATAL(4604); + } + + if (!(qual & Q_VOLATILE)) { + switch (type->type) { + case TYPEARRAY: + newtype = CDecl_NewArrayType(TYPE_POINTER(type)->target, type->size); + TYPE_POINTER(newtype)->qual |= Q_VOLATILE; + break; + case TYPEPOINTER: + newtype = CDecl_NewPointerType(TYPE_POINTER(type)->target); + TYPE_POINTER(newtype)->qual |= Q_VOLATILE; + break; + case TYPEMEMBERPOINTER: + newtype = galloc(sizeof(TypeMemberPointer)); + memcpy(newtype, type, sizeof(TypeMemberPointer)); + TYPE_MEMBER_POINTER(newtype)->qual |= Q_VOLATILE; + break; + } + + LocationSet_SetRtype(ls, newtype); + } +} + +static void AdjustTypesForVolatility(LocationSetSet *set, Object *proc, IROLinear *nd) { + if (nd->rtype && CParser_IsVolatile(nd->rtype, nd->nodeflags & ENODE_FLAG_QUALS)) + LocationSetSet_ForEach(set, AdjustTypesForVolatilityAction, NULL); +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct EvalAssignAction2Params { + CInt64 x0; + IROLinear *nd; + Boolean xC; +} EvalAssignAction2Params; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void EvalAssignAction2(LocationSet *ls, void *refcon) { + EvalAssignAction2Params *params; + CInt64 value; + IROLinear *nd; + ENodeType oper; + UInt32 stride; + Type *rtype; + PAMemoryBlock *block; + + IRO_ASSERT(4657, ls != NULL); + IRO_ASSERT(4658, refcon != NULL); + + params = refcon; + + if (!params->xC && !LocationSet_IsUnknown(ls)) { + value = params->x0; + nd = params->nd; + IRO_ASSERT(4665, nd != NULL); + oper = nd->nodetype; + + stride = LocationSet_stride(ls); + rtype = LocationSet_rtype(ls); + block = LocationSet_block(ls); + + if (block && PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_INT) { + LocationSet_Term(ls); + + switch (oper) { + case EPOSTINC: + case EPREINC: + case EADDASS: + value = CInt64_Add(*((CInt64 *) PAMemoryBlock_thing(block)), value); + break; + case EPOSTDEC: + case EPREDEC: + case ESUBASS: + value = CInt64_Sub(*((CInt64 *) PAMemoryBlock_thing(block)), value); + break; + case EMULASS: + if (IRO_IsUnsignedType(nd->rtype)) + value = CInt64_MulU(*((CInt64 *) PAMemoryBlock_thing(block)), value); + else + value = CInt64_Mul(*((CInt64 *) PAMemoryBlock_thing(block)), value); + break; + case EDIVASS: + if (CInt64_IsZero(&value)) { + if (nd->stmt->sourceoffset) { + TStreamElement *e = CPrep_CurStreamElement(); + e->tokenoffset = nd->stmt->sourceoffset; + CError_SetErrorToken(e); + } + CError_Warning(CErrorStr139); + params->xC = 1; + } else { + if (IRO_IsUnsignedType(nd->rtype)) + value = CInt64_DivU(*((CInt64 *) PAMemoryBlock_thing(block)), value); + else + value = CInt64_Div(*((CInt64 *) PAMemoryBlock_thing(block)), value); + } + break; + case EMODASS: + if (CInt64_IsZero(&value)) { + if (nd->stmt->sourceoffset) { + TStreamElement *e = CPrep_CurStreamElement(); + e->tokenoffset = nd->stmt->sourceoffset; + CError_SetErrorToken(e); + } + CError_Warning(CErrorStr139); + params->xC = 1; + } else { + if (IRO_IsUnsignedType(nd->rtype)) + value = CInt64_ModU(*((CInt64 *) PAMemoryBlock_thing(block)), value); + else + value = CInt64_Mod(*((CInt64 *) PAMemoryBlock_thing(block)), value); + } + break; + case ESHLASS: + value = CInt64_Shl(*((CInt64 *) PAMemoryBlock_thing(block)), value); + break; + case ESHRASS: + if (IRO_IsUnsignedType(nd->rtype)) + value = CInt64_ShrU(*((CInt64 *) PAMemoryBlock_thing(block)), value); + else + value = CInt64_Shr(*((CInt64 *) PAMemoryBlock_thing(block)), value); + break; + case EANDASS: + value = CInt64_And(*((CInt64 *) PAMemoryBlock_thing(block)), value); + break; + case EXORASS: + value = CInt64_Xor(*((CInt64 *) PAMemoryBlock_thing(block)), value); + break; + case EORASS: + value = CInt64_Or(*((CInt64 *) PAMemoryBlock_thing(block)), value); + break; + default: + CError_FATAL(4746); + } + + block = PAMemoryBlock_New(); + PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_INT, &value); + LocationSet_InitKnown(ls, block, cint64_zero, stride, rtype); + } else { + if (oper == EPOSTDEC || oper == EPREDEC || oper == ESUBASS) + value = CInt64_Neg(value); + + switch (oper) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EADDASS: + case ESUBASS: + value = CInt64_Add(LocationSet_field(ls), value); + if (stride) { + CInt64 tmp; + CInt64_SetLong(&tmp, stride); + value = CInt64_Mod(value, tmp); + } + SetsLocationSetField_sub_4851B0(ls, value); + break; + default: + params->xC = 1; + break; + } + } + } +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct EvalAssignActionParams { + Object *proc; + PartialTransferFunction *ptf; + IROLinear *nd; + IRONode *fnode; + LocationSetSet *srcs; + Boolean x14; + Boolean x15; + Boolean x16; +} EvalAssignActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void EvalAssignAction(LocationSet *dst, void *refcon) { + EvalAssignActionParams *params; + LocationSetSet *srcs; + + IRO_ASSERT(4797, dst != NULL); + IRO_ASSERT(4798, refcon != NULL); + + params = refcon; + + IRO_ASSERT(4802, params->proc != NULL); + IRO_ASSERT(4802, params->ptf != NULL); + IRO_ASSERT(4803, params->nd != NULL); + IRO_ASSERT(4804, params->fnode != NULL); + IRO_ASSERT(4805, params->srcs != NULL); + + srcs = params->srcs; + if ( + !params->x14 || + !LocationSetRepresentsSingleLocation(dst, params->proc, params->nd->pointsToFunction) || + LocationIsVolatile(dst, params->proc) || + LocationSet_sub_48AF30(dst) + ) { + LocationSetSet *set = LocationSetSet_New(); + LocationSetSet_Init(set); + params->x15 |= Lookup(set, &stCallingContextStack, params->proc, NULL, params->ptf, dst, params->nd->pointsToFunction, 0, params->nd->rtype); + LocationSetSet_AddSet(srcs, set); + LocationSetSet_Term(set); + LocationSetSet_Delete(set); + } + + params->x16 |= Assign(params->ptf, dst, srcs, params->proc, params->nd, params->fnode); +} + +static Boolean EvalAssign(Object *proc, IROLinear *nd, IRONode *fnode, ParamMappingFunction *map, PartialTransferFunction *ptf) { + EvalAssignActionParams params; + EvalAssignAction2Params params2; + LocationSetSet *set; + LocationSet *tmp; + PAMemoryBlock *block; + Type *type; + + IRO_ASSERT(4840, proc != NULL); + IRO_ASSERT(4841, nd != NULL); + IRO_ASSERT(4842, fnode != NULL); + IRO_ASSERT(4843, map != NULL); + IRO_ASSERT(4844, ptf != NULL); + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.ptf = ptf; + params.nd = nd; + params.fnode = fnode; + params.x15 = 0; + params.x16 = 0; + + set = LocationSetSet_New(); + params.srcs = LocationSetSet_New(); + LocationSetSet_Init(set); + LocationSetSet_Init(params.srcs); + + if (nd->type == IROLinearOp2Arg) { + IRO_ASSERT(4861, nd->u.diadic.left->type == IROLinearOp1Arg && nd->u.diadic.left->nodetype == EINDIRECT); + + params.x15 |= EvalExpr(set, proc, nd->u.diadic.left->u.monadic, &stCallingContextStack, map, ptf); + AdjustTypesForVolatility(set, proc, nd->u.diadic.left); + params.x15 |= EvalExpr(params.srcs, proc, nd->u.diadic.right, &stCallingContextStack, map, ptf); + + if (nd->nodetype != EASS) { + switch (nd->nodetype) { + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + if ( + LocationSetSet_Count(params.srcs) == 1 && + (tmp = LocationSetSet_FindFirst(params.srcs)) && + !LocationSet_IsUnknown(tmp) && + !LocationSet_stride(tmp) && + (block = LocationSet_block(tmp)) && + PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_INT + ) { + LocationSetSet_Term(params.srcs); + LocationSetSet_Init(params.srcs); + params.x15 |= EvalExpr(params.srcs, proc, nd->u.diadic.left, &stCallingContextStack, map, ptf); + + memset(¶ms2, 0, sizeof(params2)); + params2.x0 = *((CInt64 *) PAMemoryBlock_thing(block)); + IRO_TruncateValueToType(¶ms2.x0, nd->u.diadic.right->rtype); + params2.nd = nd; + params2.xC = 0; + + if (!CInt64_IsZero(¶ms2.x0)) { + LocationSetSet_ForEach(params.srcs, EvalAssignAction2, ¶ms2); + if (params2.xC) { + LocationSetSet_Term(params.srcs); + LocationSetSet_Init(params.srcs); + params.x15 |= EvalExpr(params.srcs, proc, nd->u.diadic.left, &stCallingContextStack, map, ptf); + if (!LocationSetSet_FindUnknown(params.srcs)) + LocationSetSet_ForEach(params.srcs, EvalExprAction2, (void *) &cint64_one); + } + } + } else { + LocationSetSet_Term(params.srcs); + LocationSetSet_Init(params.srcs); + params.x15 |= EvalExpr(params.srcs, proc, nd->u.diadic.left, &stCallingContextStack, map, ptf); + if (!LocationSetSet_FindUnknown(params.srcs)) + LocationSetSet_ForEach(params.srcs, EvalExprAction2, (void *) &cint64_one); + } + break; + default: + LocationSetSet_Term(params.srcs); + LocationSetSet_Init(params.srcs); + LocationSetSet_AddUnknown(params.srcs, nd->rtype, NULL, NULL); + break; + } + } + } else if (nd->type == IROLinearOp1Arg) { + IRO_ASSERT(4958, nd->u.monadic.left->type == IROLinearOp1Arg && nd->u.monadic->nodetype == EINDIRECT); + + params.x15 |= EvalExpr(set, proc, nd->u.monadic->u.monadic, &stCallingContextStack, map, ptf); + AdjustTypesForVolatility(set, proc, nd->u.monadic); + params.x15 |= EvalExpr(params.srcs, proc, nd->u.monadic, &stCallingContextStack, map, ptf); + + switch (nd->nodetype) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + memset(¶ms2, 0, sizeof(params2)); + params2.x0 = cint64_one; + params2.nd = nd; + params2.xC = 0; + + type = NULL; + if (IS_TYPE_POINTER(nd->rtype)) + type = TPTR_TARGET(nd->rtype); + else if (IS_TYPE_MEMBERPOINTER(nd->rtype)) + type = TYPE_MEMBER_POINTER(nd->rtype)->ty1; + + if (type) + CInt64_SetLong(¶ms2.x0, type->size); + + if (!CInt64_IsZero(¶ms2.x0)) { + LocationSetSet_ForEach(params.srcs, EvalAssignAction2, ¶ms2); + if (params2.xC) { + LocationSetSet_Term(params.srcs); + LocationSetSet_Init(params.srcs); + params.x15 |= EvalExpr(params.srcs, proc, nd->u.monadic, &stCallingContextStack, map, ptf); + if (!LocationSetSet_FindUnknown(params.srcs)) + LocationSetSet_ForEach(params.srcs, EvalExprAction2, (void *) &cint64_one); + } + } + break; + + default: + LocationSetSet_Term(params.srcs); + LocationSetSet_Init(params.srcs); + LocationSetSet_AddUnknown(params.srcs, nd->rtype, NULL, NULL); + break; + } + } else { + CError_FATAL(5006); + } + + if (LocationSetSet_Count(params.srcs) != 0) { + PointsToFunction *pointsToFunc; + + pointsToFunc = PointsToFunction_New(); + if (nd->pointsToFunction) + PointsToFunction_Copy(pointsToFunc, nd->pointsToFunction); + else + PointsToFunction_Init(pointsToFunc); + + params.x14 = LocationSetSet_Count(set) == 1; + LocationSetSet_ForEach(set, EvalAssignAction, ¶ms); + + if (!params.x15 && params.x16) { + if (nd->pointsToFunction) + params.x15 = !PointsToFunctions_Equal(pointsToFunc, nd->pointsToFunction); + else + params.x15 = PointsToFunction_FindFirst(pointsToFunc) != NULL; + } + + PointsToFunction_Term(pointsToFunc); + PointsToFunction_Delete(pointsToFunc); + } + + LocationSetSet_Term(set); + LocationSetSet_Term(params.srcs); + LocationSetSet_Delete(set); + LocationSetSet_Delete(params.srcs); + + return params.x15; +} + +static Boolean EvalReturn(Object *proc, IROLinear *nd, IRONode *fnode, ParamMappingFunction *map, PartialTransferFunction *ptf) { + EvalAssignActionParams params; + LocationSet *loc; + + IRO_ASSERT(5046, proc != NULL); + IRO_ASSERT(5047, nd != NULL); + IRO_ASSERT(5048, nd->type == IROLinearReturn); + IRO_ASSERT(5049, fnode != NULL); + IRO_ASSERT(5050, map != NULL); + IRO_ASSERT(5051, ptf != NULL); + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.ptf = ptf; + params.nd = nd; + params.fnode = fnode; + params.x15 = 0; + params.x16 = 0; + + if (nd->u.monadic) { + params.srcs = LocationSetSet_New(); + LocationSetSet_Init(params.srcs); + + loc = PartialTransferFunction_returnLocation(ptf); + params.x15 |= EvalExpr(params.srcs, proc, nd->u.monadic, &stCallingContextStack, map, ptf); + + if (LocationSetSet_Count(params.srcs) != 0) { + params.x14 = 1; + EvalAssignAction(loc, ¶ms); + params.x15 |= params.x16; + } + + LocationSetSet_Term(params.srcs); + LocationSetSet_Delete(params.srcs); + } + + return params.x15; +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct ApplySummaryActionParams { + ParamMappingFunction *tgtMap; + Object *proc; + IRONode *fnode; + IROLinear *nd; + PartialTransferFunction *ptf; + ParamMappingFunction *map; + LocationSet *loc; + LocationSetSet *locs; + Boolean x20; + Boolean x21; + Boolean x22; +} ApplySummaryActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void ApplySummaryAction2(ParamMapping *mapping, void *refcon) { + ApplySummaryActionParams *params; + PAMemoryBlock *block; + ExtendedParam *ep; + IROLinear *nd; + LocationSetSet *set; + EvalAssignActionParams assignParams; + + IRO_ASSERT(5108, mapping != NULL); + IRO_ASSERT(5109, refcon != NULL); + + params = refcon; + + IRO_ASSERT(5113, params->tgtMap != NULL); + IRO_ASSERT(5114, params->proc != NULL); + IRO_ASSERT(5115, params->fnode != NULL); + IRO_ASSERT(5116, params->nd != NULL); + IRO_ASSERT(5117, params->nd->type == IROLinearFunccall); + IRO_ASSERT(5118, params->ptf != NULL); + IRO_ASSERT(5119, params->map != NULL); + IRO_ASSERT(5120, params->loc != NULL); + IRO_ASSERT(5121, params->locs != NULL); + + block = LocationSet_block(params->loc); + + IRO_ASSERT(5124, block != NULL); + IRO_ASSERT(5125, PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM); + + ep = PAMemoryBlock_thing(block); + + IRO_ASSERT(5127, ep != NULL); + + if (ParamMapping_extended(mapping) == ep && (nd = ParamMapping_actual(mapping))) { + set = LocationSetSet_New(); + LocationSetSet_Init(set); + params->x21 |= EvalExpr(set, params->proc, nd, &stCallingContextStack, params->map, params->ptf); + + if (!LocationSetSet_FindUnknown(set)) { + CInt64 stride64; + CInt64 value; + + value = LocationSet_field(params->loc); + LocationSetSet_ForEach(set, EvalExprAction, &value); + + CInt64_SetULong(&stride64, LocationSet_stride(params->loc)); + LocationSetSet_ForEach(set, EvalExprAction2, &stride64); + } + + memset(&assignParams, 0, sizeof(assignParams)); + assignParams.proc = params->proc; + assignParams.ptf = params->ptf; + assignParams.nd = params->nd; + assignParams.fnode = params->fnode; + assignParams.srcs = params->locs; + assignParams.x14 = params->x20 && (LocationSetSet_Count(set) == 1); + assignParams.x15 = 0; + assignParams.x16 = 0; + LocationSetSet_ForEach(set, EvalAssignAction, &assignParams); + + LocationSetSet_Term(set); + LocationSetSet_Delete(set); + + params->x21 |= assignParams.x15; + params->x22 |= assignParams.x16; + } +} + +static void ApplySummaryAction(PointsToEntry *pte, void *refcon) { + ApplySummaryActionParams *params; + LocationSet *loc; + PAMemoryBlock *block; + + IRO_ASSERT(5175, pte != NULL); + IRO_ASSERT(5176, refcon != NULL); + + params = refcon; + + IRO_ASSERT(5180, params->tgtMap != NULL); + IRO_ASSERT(5181, params->proc != NULL); + IRO_ASSERT(5182, params->fnode != NULL); + IRO_ASSERT(5183, params->nd != NULL); + IRO_ASSERT(5184, params->nd->type == IROLinearFunccall); + IRO_ASSERT(5185, params->ptf != NULL); + IRO_ASSERT(5186, params->map != NULL); + + loc = PointsToEntry_loc(pte); + + IRO_ASSERT(5189, loc != NULL); + IRO_ASSERT(5190, !LocationSet_IsUnknown(loc)); + + block = LocationSet_block(loc); + if (block && PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) { + params->loc = loc; + params->locs = PointsToEntry_locs(pte); + pmf_sub_487C70(params->tgtMap, ApplySummaryAction2, params); + } +} + +static Boolean ApplySummary(PartialTransferFunction *tgtPTF, ParamMappingFunction *tgtMap, Object *proc, IRONode *fnode, IROLinear *nd, PartialTransferFunction *ptf, ParamMappingFunction *map, Boolean flag) { + Boolean result; + ApplySummaryActionParams params; + PointsToFunction *pointsToFunc; + + IRO_ASSERT(5208, tgtPTF != NULL); + IRO_ASSERT(5209, tgtMap != NULL); + IRO_ASSERT(5210, proc != NULL); + IRO_ASSERT(5211, fnode != NULL); + IRO_ASSERT(5212, nd != NULL); + IRO_ASSERT(5213, nd->type == IROLinearFunccall); + IRO_ASSERT(5214, ptf != NULL); + IRO_ASSERT(5215, map != NULL); + + StoreReturnedLocations(nd, tgtPTF, tgtMap); + if (tgtPTF == stUnknownPTF) { + result = KillAllAddressableLocations(proc, fnode, nd, ptf); + } else { + pointsToFunc = PointsToFunction_New(); + if (nd->pointsToFunction) + PointsToFunction_Copy(pointsToFunc, nd->pointsToFunction); + else + PointsToFunction_Init(pointsToFunc); + + memset(¶ms, 0, sizeof(params)); + params.tgtMap = tgtMap; + params.proc = proc; + params.fnode = fnode; + params.nd = nd; + params.ptf = ptf; + params.map = map; + params.loc = NULL; + params.locs = NULL; + params.x20 = flag; + params.x21 = 0; + params.x22 = 0; + + PointsToFunction_ForEach(PartialTransferFunction_finalPointsToFn(tgtPTF), ApplySummaryAction, ¶ms); + + result = params.x21; + if (!params.x21 && params.x22) { + if (nd->pointsToFunction) + result = !PointsToFunctions_Equal(pointsToFunc, nd->pointsToFunction); + else + result = PointsToFunction_FindFirst(pointsToFunc) != NULL; + } + } + + return result; +} + +static void GetPTFAction2(ParamMapping *mapping, void *refcon) { + IRO_ASSERT(5331, mapping != NULL); + + if (ParamMapping_extended(mapping)) + ParamMapping_SetExtended(mapping, NULL); +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct GetPTFActionParams { + ParamMappingFunction *map; + Object *proc; + IROLinear *nd; + PartialTransferFunction *ptf; + Boolean *needVisit; + PartialTransferFunction *x14; + PartialTransferFunction *x18; +} GetPTFActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void GetPTFAction(PartialTransferFunction *tgtPTF, void *refcon) { + GetPTFActionParams *params; + + IRO_ASSERT(5359, tgtPTF != NULL); + IRO_ASSERT(5360, refcon != NULL); + + params = refcon; + + IRO_ASSERT(5364, params->map != NULL); + IRO_ASSERT(5365, params->proc != NULL); + IRO_ASSERT(5366, params->proc != &stUnknown); + IRO_ASSERT(5367, params->nd != NULL); + IRO_ASSERT(5368, params->ptf != NULL); + IRO_ASSERT(5369, params->needVisit != NULL); + + if (!params->x18) { + if (MatchPTF(tgtPTF, params->proc, params->map, params->nd, params->ptf)) { + if (InputsHaveNewPointerValues(tgtPTF, params->ptf)) + *params->needVisit = 1; + params->x18 = tgtPTF; + } else { + pmf_sub_487C70(params->map, GetPTFAction2, NULL); + if (PTF_sub_48B980(tgtPTF) == params->nd && PTF_sub_48B970(tgtPTF) == params->ptf) + params->x14 = tgtPTF; + } + } +} + +static PartialTransferFunction *GetPTF(ParamMappingFunction *map, Object *proc, IROLinear *nd, PartialTransferFunction *ptf, Boolean *needVisit) { + PartialTransferFunction *found; + PartialTransferFunction *result; + GetPTFActionParams params; + + IRO_ASSERT(5396, map != NULL); + IRO_ASSERT(5397, proc != NULL); + IRO_ASSERT(5398, nd != NULL); + IRO_ASSERT(5399, ptf != NULL); + IRO_ASSERT(5400, needVisit != NULL); + + if (proc == &stUnknown) { + result = stUnknownPTF; + } else { + memset(¶ms, 0, sizeof(params)); + params.map = map; + params.proc = proc; + params.nd = nd; + params.ptf = PartialTransferFunction_New(); + PartialTransferFunction_Init(params.ptf, nd, ptf); + params.needVisit = needVisit; + params.x14 = NULL; + params.x18 = NULL; + + if (!proc->u.func.ptfList) { + proc->u.func.ptfList = PTFList_New(); + PTFList_Init(proc->u.func.ptfList); + } + + PTFList_ForEach(proc->u.func.ptfList, GetPTFAction, ¶ms); + + found = params.x18; + if (found && !*needVisit) { + PartialTransferFunction_Copy(result = PartialTransferFunction_New(), found); + } else { + result = stUnknownPTF; + } + + PartialTransferFunction_Term(params.ptf); + PartialTransferFunction_Delete(params.ptf); + } + + return result; +} + +static Boolean IsMeetNode(IRONode *fnode, IROLinear *nd) { + return (fnode->numpred > 1) && (fnode->first == nd); +} + +static Boolean IsExitNode(Object *proc, IRONode *fnode) { + IRO_ASSERT(5467, proc != NULL); + IRO_ASSERT(5468, fnode != NULL); + + return (fnode->numsucc == 0) && Bv_IsBitSet(FunctionFirstNode(proc)->index, fnode->dom); +} + +static Boolean SomePredecessorHasBeenVisited(Object *proc, IRONode *fnode) { + UInt16 i; + + IRO_ASSERT(5479, proc != NULL); + IRO_ASSERT(5480, fnode != NULL); + + for (i = 0; i < fnode->numpred; i++) { + if (FunctionNodeTable(proc)[fnode->pred[i]]->x3C) + return 1; + } + + return 0; +} + +static Boolean AllPredecessorsHaveBeenVisited(Object *proc, IRONode *fnode) { + UInt16 i; + + IRO_ASSERT(0, proc != NULL); + IRO_ASSERT(0, fnode != NULL); + + for (i = 0; i < fnode->numpred; i++) { + if (!FunctionNodeTable(proc)[fnode->pred[i]]->x3C) + return 0; + } + + return 1; +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct EvalProcActionParams { + Object *proc; + IRONode *fnode; + PartialTransferFunction *ptf; +} EvalProcActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void EvalProcAction2(PointsToEntry *pte, void *refcon) { + EvalProcActionParams *params; + LocationSet *dst; + PAMemoryBlock *block; + LocationSetSet *set; + IRONode *node; + + IRO_ASSERT(5525, pte != NULL); + IRO_ASSERT(5526, refcon != NULL); + + params = refcon; + + IRO_ASSERT(5530, params->proc != NULL); + IRO_ASSERT(5531, params->fnode != NULL); + IRO_ASSERT(5532, params->ptf != NULL); + + dst = PointsToEntry_loc(pte); + + IRO_ASSERT(5535, dst != NULL); + IRO_ASSERT(5536, !LocationSet_IsUnknown(dst)); + + block = LocationSet_block(dst); + + if (block && (LocationSet_sub_48AF30(dst) || PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM)) { + set = LocationSetSet_New(); + LocationSetSet_Init(set); + LocationSetSet_AddSet(set, PointsToEntry_locs(pte)); + + for (node = FunctionFirstNode(params->proc); node; node = node->nextnode) { + if (node->x3C && node != params->fnode && IsExitNode(params->proc, node)) { + if (node->last->pointsToFunction) + Lookup(set, &stCallingContextStack, params->proc, NULL, params->ptf, dst, node->last->pointsToFunction, 0, NULL); + } + } + + Assign(params->ptf, dst, set, params->proc, NULL, NULL); + + LocationSetSet_Term(set); + LocationSetSet_Delete(set); + } +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct AssignEachInPointsToFunctionActionParams { + Object *proc; + IROLinear *nd; + IRONode *fnode; + PartialTransferFunction *ptf; + Boolean x10; +} AssignEachInPointsToFunctionActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void AssignEachInPointsToFunctionAction(PointsToEntry *pte, void *refcon) { + AssignEachInPointsToFunctionActionParams *params; + LocationSet *dst; + LocationSetSet *srcs; + + IRO_ASSERT(5577, pte != NULL); + IRO_ASSERT(5578, refcon != NULL); + + params = refcon; + + IRO_ASSERT(5582, params->proc != NULL); + IRO_ASSERT(5583, params->nd != NULL); + IRO_ASSERT(5584, params->fnode != NULL); + IRO_ASSERT(5585, params->ptf != NULL); + + dst = PointsToEntry_loc(pte); + + srcs = LocationSetSet_New(); + LocationSetSet_Init(srcs); + LocationSetSet_AddSet(srcs, PointsToEntry_locs(pte)); + params->x10 |= Assign(params->ptf, dst, srcs, params->proc, params->nd, params->fnode); + LocationSetSet_Term(srcs); + LocationSetSet_Delete(srcs); +} + +static void AssignEachInPointsToFunction(PointsToFunction *pointsTo, void *refcon) { + AssignEachInPointsToFunctionActionParams *params; + PointsToFunction *pointsToFunc; + + IRO_ASSERT(5602, pointsTo != NULL); + IRO_ASSERT(5603, refcon != NULL); + + params = refcon; + + IRO_ASSERT(5607, params->nd != NULL); + + pointsToFunc = PointsToFunction_New(); + if (params->nd->pointsToFunction) + PointsToFunction_Copy(pointsToFunc, params->nd->pointsToFunction); + else + PointsToFunction_Init(pointsToFunc); + + if (PointsToFunction_FindFirst(pointsToFunc)) { + PointsToFunction_ForEach(pointsTo, AssignEachInPointsToFunctionAction, params); + } else { + if (!params->nd->pointsToFunction) + params->nd->pointsToFunction = PointsToFunction_New(); + else + PointsToFunction_Term(params->nd->pointsToFunction); + + PointsToFunction_Copy(params->nd->pointsToFunction, pointsTo); + params->x10 = 1; + } + + if (params->x10) { + if (params->nd->pointsToFunction) + params->x10 = !PointsToFunctions_Equal(pointsToFunc, params->nd->pointsToFunction); + else + params->x10 = PointsToFunction_FindFirst(pointsToFunc) != NULL; + } + + PointsToFunction_Term(pointsToFunc); + PointsToFunction_Delete(pointsToFunc); +} + +static Boolean ObjectIsAFunctionArgument(Object *proc, Object *obj) { + ObjectList *list; + + IRO_ASSERT(5643, proc != NULL); + IRO_ASSERT(5644, proc != &stUnknown); + IRO_ASSERT(5645, obj != NULL); + + if (obj->datatype == DLOCAL) { + for (list = FunctionArguments(proc); list; list = list->next) { + if (obj == list->object) + return 1; + } + } + + return 0; +} + +static Boolean ObjectIsARealFunctionArgument(Object *proc, Object *obj) { + ObjectList *list; + + IRO_ASSERT(5661, proc != NULL); + IRO_ASSERT(5662, proc != &stUnknown); + IRO_ASSERT(5663, obj != NULL); + + if (obj->datatype == DLOCAL && proc == cscope_currentfunc) { + for (list = arguments; list; list = list->next) { + if (obj == list->object) + return 1; + } + } + + return 0; +} + +static void AddLocalVarsAddressedByExceptionUses(Object *var) { + IRO_ASSERT(5699, var != NULL); + IRO_ASSERT(5700, stExceptionFNode != NULL); + IRO_ASSERT(5701, stExceptionFNode->addressed != NULL); + + if (var->datatype == DLOCAL) + ObjectSet_sub_4867D0(stExceptionFNode->addressed, var); +} + +static Boolean LinearNodeIsInFlowgraphNode(IROLinear *nd, IRONode *fnode) { + IROLinear *first; + IROLinear *last; + IROLinear *scan; + + if (fnode && (first = fnode->first) && (last = fnode->last)) { + for (scan = first; scan && scan != last->next; scan = scan->next) { + if (scan == nd) + return 1; + } + } + + return 0; +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +static struct { + Object *proc; + IRONode *fnode; + ParamMappingFunction *map; + PartialTransferFunction *ptf; + PointsToFunction *pointsToFunc; + Boolean *changed; + Boolean x18; + Boolean x19; +} stEvalProcActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void EvalProcAction(IROLinear *Int, Boolean flag) { + Boolean *changed; + Boolean result; + Object *proc; + PartialTransferFunction *ptf; + Boolean x18; + Boolean x19; + IRONode *fnode; + PointsToFunction *pointsToFunc; + ParamMappingFunction *map; + Object *obj; + AssignEachInPointsToFunctionActionParams params; + + static int userBreakCounter; + + if (!flag && !Int->x1E) { + IRO_ASSERT(5748, Int != NULL); + IRO_ASSERT(5749, stEvalProcActionParams.changed != NULL); + + proc = stEvalProcActionParams.proc; + fnode = stEvalProcActionParams.fnode; + map = stEvalProcActionParams.map; + ptf = stEvalProcActionParams.ptf; + pointsToFunc = stEvalProcActionParams.pointsToFunc; + changed = stEvalProcActionParams.changed; + x18 = stEvalProcActionParams.x18; + x19 = stEvalProcActionParams.x19; + + IRO_ASSERT(5760, proc != NULL); + IRO_ASSERT(5761, fnode != NULL); + IRO_ASSERT(5762, map != NULL); + IRO_ASSERT(5763, ptf != NULL); + + if (++userBreakCounter > 40) { + IRO_CheckForUserBreak(); + userBreakCounter = 0; + } + + result = 0; + + if (x19 && Int->pointsToFunction) { + PointsToFunction_Term(Int->pointsToFunction); + PointsToFunction_Delete(Int->pointsToFunction); + Int->pointsToFunction = NULL; + } + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.nd = Int; + params.fnode = fnode; + params.ptf = ptf; + params.x10 = 0; + + if (x18) { + PointsToFunction *initial = PartialTransferFunction_initialPointsToFn(ptf); + if (fnode == FunctionFirstNode(proc) && initial) { + AssignEachInPointsToFunction(initial, ¶ms); + result |= params.x10; + } + result |= EvalMeet(proc, fnode, Int, ptf); + pointsToFunc = Int->pointsToFunction; + x18 = 0; + } else if (!Int->pointsToFunction) { + if (pointsToFunc) + AssignEachInPointsToFunction(pointsToFunc, ¶ms); + result |= params.x10; + pointsToFunc = Int->pointsToFunction; + } + + if (IRO_IsAssignment(Int)) { + if (Int->flags & IROLF_4000) + longjmp(stAbortPointerAnalysis, 1); + result |= EvalAssign(proc, Int, fnode, map, ptf); + pointsToFunc = Int->pointsToFunction; + } else if (Int->type == IROLinearReturn) { + result |= EvalReturn(proc, Int, fnode, map, ptf); + pointsToFunc = Int->pointsToFunction; + } else if (Int->type == IROLinearFunccall) { + if (Int->flags & IROLF_4000) + longjmp(stAbortPointerAnalysis, 1); + if (Int->stmt && IRO_FunctionCallMightThrowException(Int)) { + stExceptionFNode = fnode; + IRO_WalkExcActions(Int->stmt->dobjstack, AddLocalVarsAddressedByExceptionUses); + } + result |= EvalCall(proc, fnode, Int, map, ptf); + pointsToFunc = Int->pointsToFunction; + } else if (Int->type == IROLinearOp1Arg && Int->nodetype == EINDIRECT && (!(Int->flags & IROLF_Assigned) || (Int->flags & IROLF_Used))) { + result |= EvalExpr(NULL, proc, Int, &stCallingContextStack, map, ptf); + } else if (Int->type == IROLinearOperand && !(Int->flags & IROLF_Ind) && Int->u.node->type == EOBJREF && (obj = Int->u.node->data.objref) && obj->datatype == DLOCAL) { + ObjectSet_sub_4867D0(fnode->addressed, obj); + } else if (Int->type == IROLinearAsm) { + IAEffects effects; + int i; + CodeGen_GetAsmEffects(Int->u.asm_stmt, &effects); + for (i = 0; i < effects.numoperands; i++) { + obj = effects.operands[i].object; + if (obj && obj->datatype == DLOCAL && effects.operands[i].type == IAEffect_3) { + ObjectSet_sub_4867D0(fnode->addressed, obj); + } + } + } + + if (result && Int != fnode->last && fnode->last->pointsToFunction) { + PointsToFunction_Term(fnode->last->pointsToFunction); + PointsToFunction_Delete(fnode->last->pointsToFunction); + fnode->last->pointsToFunction = NULL; + } + + *changed |= result; + x19 |= result; + + stEvalProcActionParams.pointsToFunc = pointsToFunc; + stEvalProcActionParams.x18 = x18; + stEvalProcActionParams.x19 = x19; + + Int->x1E = 1; + + if (Int->type != IROLinearReturn) { + IROLinear *father = IRO_LocateFather(Int); + if (father && father->type == IROLinearReturn) { + if (LinearNodeIsInFlowgraphNode(father, fnode)) + EvalProcAction(father, 0); + else + longjmp(stAbortPointerAnalysis, 1); + } + } + } +} + +static void EvalProc(Object *proc, ParamMappingFunction *map, PartialTransferFunction *ptf) { + IRONode *fnode; + IRONode *pred; + IROLinear *nd; + UInt32 passCount; + Boolean changed; + UInt16 i; + AssignEachInPointsToFunctionActionParams assignParams; + EvalProcActionParams params; + + IRO_ASSERT(5964, proc != NULL); + IRO_ASSERT(5965, map != NULL); + IRO_ASSERT(5966, ptf != NULL); + + for (fnode = FunctionFirstNode(proc); fnode; fnode = fnode->nextnode) + fnode->x3C = 0; + + passCount = 0; + do { + clock(); + changed = 0; + for (fnode = FunctionFirstNode(proc); fnode; fnode = fnode->nextnode) { + if (fnode->last && ((fnode->numpred == 0) || SomePredecessorHasBeenVisited(proc, fnode))) { + clock(); + if (!fnode->addressed) { + fnode->addressed = ObjectSet_New(); + ObjectSet_Init(fnode->addressed); + } + + for (i = 0; i < fnode->numpred; i++) { + pred = FunctionNodeTable(proc)[fnode->pred[i]]; + if (pred->addressed) + ObjectSet_sub_48C590(fnode->addressed, pred->addressed); + } + + memset(&stEvalProcActionParams, 0, sizeof(stEvalProcActionParams)); + stEvalProcActionParams.proc = proc; + stEvalProcActionParams.fnode = fnode; + stEvalProcActionParams.map = map; + stEvalProcActionParams.ptf = ptf; + stEvalProcActionParams.pointsToFunc = NULL; + stEvalProcActionParams.changed = &changed; + stEvalProcActionParams.x18 = 1; + stEvalProcActionParams.x19 = 0; + + for (nd = fnode->first; nd && nd != fnode->last->next; nd = nd->next) + nd->x1E = 0; + IRO_WalkInts(fnode->first, fnode->last, EvalProcAction); + + if (stEvalProcActionParams.x18 || !fnode->last->pointsToFunction) { + memset(&assignParams, 0, sizeof(assignParams)); + assignParams.proc = proc; + assignParams.nd = fnode->last; + assignParams.fnode = fnode; + assignParams.ptf = ptf; + assignParams.x10 = 0; + if (stEvalProcActionParams.x18) { + PointsToFunction *initial = PartialTransferFunction_initialPointsToFn(ptf); + if (fnode == FunctionFirstNode(proc) && initial) { + AssignEachInPointsToFunction(initial, &assignParams); + changed |= assignParams.x10; + } + changed |= EvalMeet(proc, fnode, fnode->last, ptf); + stEvalProcActionParams.x18 = 0; + } else { + if (stEvalProcActionParams.pointsToFunc) + AssignEachInPointsToFunction(stEvalProcActionParams.pointsToFunc, &assignParams); + changed |= assignParams.x10; + } + } + + fnode->x3C = 1; + clock(); + } + } + + clock(); + if (++passCount > 32) + CError_FATAL(6072); + } while (changed); + + if (passCount > stMaxPassCount) + stMaxPassCount = passCount; + + PartialTransferFunction_sub_48A610(ptf, 1); + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.ptf = ptf; + for (fnode = FunctionFirstNode(proc); fnode; fnode = fnode->nextnode) { + if (fnode->x3C && IsExitNode(proc, fnode) && fnode->last->pointsToFunction) { + params.fnode = fnode; + PointsToFunction_ForEach(fnode->last->pointsToFunction, EvalProcAction2, ¶ms); + } + } +} + +static void PointerAnalysis_Init(void) { + stCallingContextStack = Stack_New(); + Stack_Init(stCallingContextStack); + + stUnknownPTF = PartialTransferFunction_New(); + PartialTransferFunction_Init(stUnknownPTF, NULL, NULL); + + stExtParamSet = AllocsExtParamSet_sub_4876C0(); + InitsExtParamSet_sub_4876A0(stExtParamSet); + + stPTFList = PTFList_New(); + PTFList_Init(stPTFList); +} + +static void CleanseLocationSet(LocationSet *loc, void *refcon) { + PAMemoryBlock *block; + PALocalVar *local; + + IRO_ASSERT(6161, loc != NULL); + IRO_ASSERT(6162, refcon == NULL); + + if ( + !LocationSet_IsUnknown(loc) && + (block = LocationSet_block(loc)) && + PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_LOCALVAR && + (local = PAMemoryBlock_thing(block)) + ) { + PALocalVar_SetSth_sub_4847C0(local, NULL); + } +} + +static void CleansePointsToEntry(PointsToEntry *pte, void *refcon) { + IRO_ASSERT(6177, pte != NULL); + IRO_ASSERT(6178, refcon == NULL); + + CleanseLocationSet(PointsToEntry_loc(pte), NULL); + LocationSetSet_ForEach(PointsToEntry_locs(pte), CleanseLocationSet, NULL); +} + +static void PointerAnalysis_TermAction4(PartialTransferFunction *ptf, void *refcon) { + IRO_ASSERT(6187, ptf != NULL); + IRO_ASSERT(6188, refcon == NULL); + + if (ptf != stUnknownPTF) { + PointsToFunction_ForEach(PartialTransferFunction_initialPointsToFn(ptf), CleansePointsToEntry, NULL); + PointsToFunction_ForEach(PartialTransferFunction_finalPointsToFn(ptf), CleansePointsToEntry, NULL); + } +} + +static void PointerAnalysis_TermAction3(ExtendedParam *ep) { + ExtendedParam_Term(ep); + ExtendedParam_Delete(ep); +} + +static void PointerAnalysis_TermAction2(Object *obj, void *refcon) { + ObjectSet *objSet; + Object *proc; + ObjectList *list; + + objSet = refcon; + + if (!ObjectIsAnExtendedParamCandidate(obj)) { + if ( + obj->datatype == DLOCAL && + obj->u.var.info && + (proc = obj->u.var.info->func) && + ObjectIsAFunction(proc) && + proc->u.func.argList + ) { + for (list = proc->u.func.argList; list; list = list->next) { + if (obj == list->object) + break; + } + + if (!list) + ObjectSet_sub_4867D0(objSet, obj); + } else { + ObjectSet_sub_4867D0(objSet, obj); + } + } +} + +static void PointerAnalysis_TermAction1(ExtendedParam *ep, void *refcon) { + ObjectSet *objSet; + ObjectSet *epObjSet; + Object *obj; + + objSet = ObjectSet_New(); + ObjectSet_Init(objSet); + + epObjSet = ExtendedParam_objectSet(ep); + obj = NULL; + ObjectSet_ForEach(epObjSet, FindGlobalObjectAction, &obj); + if (obj) { + ObjectSet_ForEach(epObjSet, PointerAnalysis_TermAction2, objSet); + if (ObjectSet_FindFirst(objSet)) + EP_sub_48C850(ep, objSet); + } + + ObjectSet_Term(objSet); + ObjectSet_Delete(objSet); +} + +static void PointerAnalysis_Term(void) { + if (stExtParamSet) { + MaybeWalkExtParamSet_sub_48CBE0(stExtParamSet, PointerAnalysis_TermAction1, NULL); + TermsExtParamSet_sub_48CB00(stExtParamSet); + FreesExtParamSet_sub_48CAE0(stExtParamSet); + stExtParamSet = NULL; + } + + if (stPTFList) { + PTFList_ForEach(stPTFList, PointerAnalysis_TermAction4, NULL); + PTFList_Term(stPTFList); + PTFList_Delete(stPTFList); + stPTFList = NULL; + } + + PartialTransferFunction_Term(stUnknownPTF); + PartialTransferFunction_Delete(stUnknownPTF); + stUnknownPTF = NULL; + + Stack_Term(&stCallingContextStack); + Stack_Delete(stCallingContextStack); + stCallingContextStack = NULL; +} + +static void InvalidatePointsToFunctions(Object *proc) { + IRONode *fnode; + IROLinear *nd; + + IRO_ASSERT(6302, proc != NULL); + + for (fnode = FunctionFirstNode(proc); fnode; fnode = fnode->nextnode) { + if (fnode->last) { + if (fnode->addressed) { + ObjectSet_Term(fnode->addressed); + ObjectSet_Delete(fnode->addressed); + fnode->addressed = NULL; + } + + for (nd = fnode->first; nd && nd != fnode->last->next; nd = nd->next) { + if (nd->pointsToFunction) { + PointsToFunction_Term(nd->pointsToFunction); + PointsToFunction_Delete(nd->pointsToFunction); + nd->pointsToFunction = NULL; + } + } + } + } +} + +static void InitialSetup(void) { +} + +static void PointerAnalysis_HeapErrorProc(void) { + longjmp(stAbortPointerAnalysis, 2); +} + +void PointerAnalysis_Setup(void) { + IRO_InitializeAllocator(); + stExtendedParamNum = 0; + stParamObjs = NULL; + stMaxPassCount = 0; +} + +void PointerAnalysis_Cleanup(void) { + ObjectList *list; + ObjectList *next; + + for (list = stParamObjs; list; list = next) { + IRO_free(list->object); + next = list->next; + IRO_free(list); + } + stParamObjs = NULL; + IRO_TerminateAllocator(); +} + +void IRO_AnalyzePointers(Object *function) { + EvalCallActionParams params; + IROLinear nd; + IRONode fnode; + int code; + volatile heaperror_t saveheaperror; + + IRO_ASSERT(6393, function != NULL); + + PointerAnalysis_Init(); + + memset(¶ms, 0, sizeof(params)); + memset(&nd, 0, sizeof(nd)); + nd.type = IROLinearFunccall; + memset(&fnode, 0, sizeof(fnode)); + params.proc = &stUnknown; + params.fnode = &fnode; + params.nd = &nd; + params.ptf = stUnknownPTF; + params.map = NULL; + params.x18 = 0; + params.x19 = 0; + params.x1A = 1; + + stCurrentProc = FindMainEntryPoint(function); + + if ((code = setjmp(stAbortPointerAnalysis)) == 0) { + saveheaperror = getheaperror(); + setheaperror(PointerAnalysis_HeapErrorProc); + InitialSetup(); + EvalCallAction(stCurrentProc, ¶ms); + PointerAnalysis_Term(); + stCurrentProc = NULL; + setheaperror(saveheaperror); + } else { + setheaperror(saveheaperror); + InvalidatePointsToFunctions(stCurrentProc); + PointerAnalysis_Term(); + stCurrentProc = NULL; + if (code == 2 && saveheaperror) + saveheaperror(); + } +} + +static void RemoveRestrictedExtendedParamsAction(LocationSet *ls, void *refcon) { + LocationSetSet *locs; + PAMemoryBlock *block; + ExtendedParam *ep; + ObjectSet *objSet; + Object *obj; + + locs = refcon; + + if ( + !LocationSet_IsUnknown(ls) && + (block = LocationSet_block(ls)) && + PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM && + (ep = PAMemoryBlock_thing(block)) + ) { + objSet = ExtendedParam_objectSet(ep); + if ( + ObjectSet_Count(objSet) == 1 && + (obj = ObjectSet_FindFirst(objSet)) && + ObjectIsRestrictQualified(obj) + ) { + LocationSetSet_Add(locs, ls); + } + } +} + +static void RemoveRestrictedExtendedParams(LocationSetSet *locs) { + LocationSetSet *set; + + set = LocationSetSet_New(); + LocationSetSet_Init(set); + LocationSetSet_ForEach(locs, RemoveRestrictedExtendedParamsAction, set); + LocationSetSet_sub_488700(locs, set); + LocationSetSet_Term(set); + LocationSetSet_Delete(set); +} + +Boolean PointerAnalysis_TwoLinearNodePointerExprsMightAlias(Object *proc, IROLinear *nd1, IROLinear *nd2) { + LocationSetSet *lss1; + LocationSetSet *lss2; + PointsToFunction *pointsTo1; + PointsToFunction *pointsTo2; + PointsToFunction *savePointsTo1; + PointsToFunction *savePointsTo2; + FindAliasingParams params; + + pointsTo1 = nd1->pointsToFunction; + pointsTo2 = nd2->pointsToFunction; + if (!pointsTo1) + pointsTo1 = pointsTo2; + if (!pointsTo2) + pointsTo2 = pointsTo1; + + if (copts.opt_pointer_analysis_mode == 2 && !is_typeequal(nd1->rtype, nd2->rtype)) + return 0; + if (!pointsTo1 || !pointsTo2) + return 1; + + lss1 = LocationSetSet_New(); + LocationSetSet_Init(lss1); + lss2 = LocationSetSet_New(); + LocationSetSet_Init(lss2); + + savePointsTo1 = nd1->pointsToFunction; + nd1->pointsToFunction = pointsTo1; + EvalExpr(lss1, proc, nd1, NULL, NULL, NULL); + nd1->pointsToFunction = savePointsTo1; + + savePointsTo2 = nd2->pointsToFunction; + nd2->pointsToFunction = pointsTo2; + EvalExpr(lss2, proc, nd2, NULL, NULL, NULL); + nd2->pointsToFunction = savePointsTo2; + + memset(¶ms, 0, sizeof(params)); + params.x8 = 0; + params.x0 = lss2; + LocationSetSet_ForEach(lss1, FindAliasingAction, ¶ms); + + if (!params.x8) { + params.x0 = lss1; + LocationSetSet_ForEach(lss2, FindAliasingAction, ¶ms); + + if (!params.x8) { + RemoveRestrictedExtendedParams(lss1); + RemoveRestrictedExtendedParams(lss2); + ExpandLocationSetSetToActuals(&stCallingContextStack, NULL, lss1); + ExpandLocationSetSetToActuals(&stCallingContextStack, NULL, lss2); + + params.x0 = lss2; + LocationSetSet_ForEach(lss1, FindAliasingAction, ¶ms); + + if (!params.x8) { + params.x0 = lss1; + LocationSetSet_ForEach(lss2, FindAliasingAction, ¶ms); + } + } + } + + LocationSetSet_Term(lss1); + LocationSetSet_Delete(lss1); + LocationSetSet_Term(lss2); + LocationSetSet_Delete(lss2); + + return params.x8; +} + +Boolean PointerAnalysis_TwoENodePointerExprsMightAlias(Object *proc, ENode *nd1, ENode *nd2) { + LocationSetSet *lss1; + LocationSetSet *lss2; + PointsToFunction *pointsTo1; + PointsToFunction *pointsTo2; + PointsToFunction *savePointsTo1; + PointsToFunction *savePointsTo2; + FindAliasingParams params; + + pointsTo1 = nd1->pointsTo; + pointsTo2 = nd2->pointsTo; + if (!pointsTo1) + pointsTo1 = pointsTo2; + if (!pointsTo2) + pointsTo2 = pointsTo1; + + if (copts.opt_pointer_analysis_mode == 2 && !is_typeequal(nd1->rtype, nd2->rtype)) + return 0; + if (!pointsTo1 || !pointsTo2) + return 1; + + lss1 = LocationSetSet_New(); + LocationSetSet_Init(lss1); + lss2 = LocationSetSet_New(); + LocationSetSet_Init(lss2); + + savePointsTo1 = nd1->pointsTo; + nd1->pointsTo = pointsTo1; + EvalENodeExpr(lss1, proc, nd1, NULL, NULL, NULL); + nd1->pointsTo = savePointsTo1; + + savePointsTo2 = nd2->pointsTo; + nd2->pointsTo = pointsTo2; + EvalENodeExpr(lss2, proc, nd2, NULL, NULL, NULL); + nd2->pointsTo = savePointsTo2; + + memset(¶ms, 0, sizeof(params)); + params.x8 = 0; + params.x0 = lss2; + LocationSetSet_ForEach(lss1, FindAliasingAction, ¶ms); + + if (!params.x8) { + params.x0 = lss1; + LocationSetSet_ForEach(lss2, FindAliasingAction, ¶ms); + + if (!params.x8) { + RemoveRestrictedExtendedParams(lss1); + RemoveRestrictedExtendedParams(lss2); + ExpandLocationSetSetToActuals(&stCallingContextStack, NULL, lss1); + ExpandLocationSetSetToActuals(&stCallingContextStack, NULL, lss2); + + params.x0 = lss2; + LocationSetSet_ForEach(lss1, FindAliasingAction, ¶ms); + + if (!params.x8) { + params.x0 = lss1; + LocationSetSet_ForEach(lss2, FindAliasingAction, ¶ms); + } + } + } + + LocationSetSet_Term(lss1); + LocationSetSet_Delete(lss1); + LocationSetSet_Term(lss2); + LocationSetSet_Delete(lss2); + + return params.x8; +} + +Boolean PointerAnalysis_IsLinearNodePointerExprDefinite(Object *proc, IROLinear *nd) { + LocationSetSet *lss; + LocationSet *loc; + Boolean result; + + if (!nd->pointsToFunction) + return 0; + + lss = LocationSetSet_New(); + LocationSetSet_Init(lss); + EvalExpr(lss, proc, nd, NULL, NULL, NULL); + + result = + (LocationSetSet_Count(lss) == 1) && + (loc = LocationSetSet_FindFirst(lss)) && + LocationSetRepresentsSingleLocation(loc, NULL, NULL); + + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + + return result; +} + +Boolean PointerAnalysis_IsENodePointerExprDefinite(Object *proc, ENode *nd) { + LocationSetSet *lss; + LocationSet *loc; + Boolean result; + + if (!nd->pointsTo) + return 0; + + lss = LocationSetSet_New(); + LocationSetSet_Init(lss); + EvalENodeExpr(lss, proc, nd, NULL, NULL, NULL); + + result = + (LocationSetSet_Count(lss) == 1) && + (loc = LocationSetSet_FindFirst(lss)) && + LocationSetRepresentsSingleLocation(loc, NULL, NULL); + + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + + return result; +} + +Boolean PointerAnalysis_IsVariableValueDefinite(Object *proc, VarRecord *var, PointsToFunction *pointsTo) { + LocationSetSet *lss; + LocationSet *loc; + Boolean result; + + if (!pointsTo) + return 0; + + lss = LocationSetSet_New(); + LocationSetSet_Init(lss); + EvalVariable(lss, proc, var, pointsTo, NULL, NULL, NULL); + + result = + (LocationSetSet_Count(lss) == 1) && + (loc = LocationSetSet_FindFirst(lss)) && + LocationSetRepresentsSingleLocation(loc, NULL, NULL); + + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + + return result; +} + +static void FindGlobalObjectAction(Object *object, void *refcon) { + if (ObjectIsAnExtendedParamCandidate(object)) { + Object **ptr = refcon; + *ptr = object; + } +} + +static void GetDefiniteObjectOfExtendedParamLoc(LocationSet *loc, Object **resultObj, CInt64 *resultField) { + Object *obj; + CInt64 field; + PAMemoryBlock *block; + ExtendedParam *ep; + ObjectSet *objSet; + LocationSetSet *locs; + LocationSet *tmp; + PALocalVar *local; + + IRO_ASSERT(6763, loc != NULL); + IRO_ASSERT(6764, resultObj != NULL); + IRO_ASSERT(6765, resultField != NULL); + + obj = NULL; + field = LocationSet_field(loc); + block = LocationSet_block(loc); + + if (block && PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) { + if ((ep = PAMemoryBlock_thing(block)) && (objSet = ExtendedParam_objectSet(ep))) { + IRO_ASSERT(6777, obj == NULL); + ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj); + } + } + + if (!obj) { + locs = LocationSetSet_New(); + LocationSetSet_Init(locs); + GetActualLocsOfExtendedParam(locs, loc, NULL, &stCallingContextStack, NULL, 0); + + if ( + LocationSetSet_Count(locs) == 1 && + (tmp = LocationSetSet_FindFirst(locs)) && + !LocationSet_IsUnknown(tmp)) + { + field = CInt64_Add(field, LocationSet_field(tmp)); + if ( + (block = LocationSet_block(tmp)) && + PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM && + (ep = PAMemoryBlock_thing(block)) && + (objSet = ExtendedParam_objectSet(ep)) + ) + { + IRO_ASSERT(6801, obj == NULL); + ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj); + } else if ( + (block = LocationSet_block(tmp)) && + PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_LOCALVAR && + (local = PAMemoryBlock_thing(block)) + ) + { + obj = GetLocalObject(local, &stUnknown, 0); + } + } + + LocationSetSet_Term(locs); + LocationSetSet_Delete(locs); + } + + *resultObj = obj; + *resultField = field; +} + +static void CreateExpressionForLocationSet(LocationSet *loc, IROList *list, Type *rtype, Object *proc) { + CInt64 field; + PAMemoryBlock *block; + PAMemoryBlockKind kind; + void *thing; + IROLinear *nd; + Object *obj; + + IRO_ASSERT(6833, loc != NULL); + IRO_ASSERT(6834, !LocationSet_IsUnknown(loc)); + IRO_ASSERT(6835, LocationSet_stride(loc) == 0); + IRO_ASSERT(6836, list != NULL); + IRO_ASSERT(6837, rtype != NULL); + IRO_ASSERT(6838, proc != NULL); + + field = LocationSet_field(loc); + block = LocationSet_block(loc); + kind = PAMemoryBlock_kind(block); + thing = PAMemoryBlock_thing(block); + nd = NULL; + + switch (kind) { + case PAMEMORYBLOCKKIND_EXTENDEDPARAM: + GetDefiniteObjectOfExtendedParamLoc(loc, &obj, &field); + if (obj) { + nd = IRO_NewLinear(IROLinearOperand); + nd->u.node = create_objectrefnode(obj); + nd->rtype = rtype; + nd->index = ++IRO_NumLinear; + IRO_AddToList(nd, list); + } + break; + case PAMEMORYBLOCKKIND_LOCALVAR: + obj = GetLocalObject(thing, proc, 0); + if (obj) { + if (ObjectIsAFunctionArgument(proc, obj) && obj->u.var.realObj) + obj = obj->u.var.realObj; + nd = IRO_NewLinear(IROLinearOperand); + nd->u.node = create_objectrefnode(obj); + nd->rtype = rtype; + nd->index = ++IRO_NumLinear; + IRO_AddToList(nd, list); + } + break; + case PAMEMORYBLOCKKIND_INT: + if (IS_TYPE_INT(rtype)) { + nd = IRO_NewIntConst(*((CInt64 *) thing), rtype); + IRO_AddToList(nd, list); + } + break; + case PAMEMORYBLOCKKIND_6: + break; + default: + CError_FATAL(6894); + } + + if (nd && !CInt64_IsZero(&field)) { + IROLinear *nd2; + IROLinear *nd3; + + nd2 = IRO_NewIntConst(field, TYPE(&stunsignedlong)); + IRO_AddToList(nd2, list); + + nd3 = IRO_NewLinear(IROLinearOp2Arg); + nd3->nodetype = EADD; + nd3->index = ++IRO_NumLinear; + nd3->rtype = rtype; + nd3->u.diadic.left = nd; + nd3->u.diadic.right = nd2; + IRO_AddToList(nd3, list); + } +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct LookupLinearExprActionParams { + Object *proc; + Type *indirectType; + IROListNode **list; +} LookupLinearExprActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void LookupLinearExprAction(LocationSet *loc, void *refcon) { + LookupLinearExprActionParams *params; + IROListNode *list; + + IRO_ASSERT(6926, loc != NULL); + IRO_ASSERT(6927, refcon != NULL); + + params = refcon; + + IRO_ASSERT(6931, params->proc != NULL); + IRO_ASSERT(6932, params->indirectType != NULL); + IRO_ASSERT(6933, params->list != NULL); + + list = *params->list = IRO_malloc(sizeof(IROListNode)); + IRO_InitList(&list->list); + list->nextList = NULL; + + if (!LocationSet_IsUnknown(loc) && LocationSetRepresentsSingleLocation(loc, NULL, NULL)) + CreateExpressionForLocationSet(loc, &list->list, params->indirectType, params->proc); + + params->list = &list->nextList; +} + +void PointerAnalysis_LookupLinearNodePointerExpr(Object *proc, IROLinear *indirect, IROListNode **list) { + LocationSetSet *set; + LookupLinearExprActionParams params; + + IRO_ASSERT(6957, indirect != NULL); + + if (indirect->pointsToFunction) { + set = LocationSetSet_New(); + LocationSetSet_Init(set); + EvalExpr(set, proc, indirect, NULL, NULL, NULL); + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.indirectType = indirect->rtype; + params.list = list; + + LocationSetSet_ForEach(set, LookupLinearExprAction, ¶ms); + LocationSetSet_Term(set); + LocationSetSet_Delete(set); + } +} + +static void CreateENodeForLocationSet(LocationSet *loc, ENode **resultNode, Type *rtype, Object *proc) { + CInt64 field; + PAMemoryBlock *block; + PAMemoryBlockKind kind; + void *thing; + ENode *nd; + Object *obj; + + IRO_ASSERT(0, loc != NULL); + IRO_ASSERT(0, !LocationSet_IsUnknown(loc)); + IRO_ASSERT(0, LocationSet_stride(loc) == 0); + IRO_ASSERT(0, resultNode != NULL); + IRO_ASSERT(0, rtype != NULL); + IRO_ASSERT(0, proc != NULL); + + field = LocationSet_field(loc); + block = LocationSet_block(loc); + kind = PAMemoryBlock_kind(block); + thing = PAMemoryBlock_thing(block); + nd = NULL; + + switch (kind) { + case PAMEMORYBLOCKKIND_EXTENDEDPARAM: + GetDefiniteObjectOfExtendedParamLoc(loc, &obj, &field); + if (obj) { + nd = create_objectrefnode(obj); + nd->rtype = rtype; + } + break; + case PAMEMORYBLOCKKIND_LOCALVAR: + obj = GetLocalObject(thing, proc, 0); + if (obj) { + if (ObjectIsAFunctionArgument(proc, obj) && obj->u.var.realObj) + obj = obj->u.var.realObj; + nd = create_objectrefnode(obj); + nd->rtype = rtype; + } + break; + case PAMEMORYBLOCKKIND_INT: + if (IS_TYPE_INT(rtype)) { + nd = IRO_NewENode(EINTCONST); + nd->data.intval = *((CInt64 *) thing); + nd->rtype = rtype; + } + break; + case PAMEMORYBLOCKKIND_6: + break; + default: + CError_FATAL(7040); + } + + if (nd && !CInt64_IsZero(&field)) { + ENode *nd2; + ENode *nd3; + + nd2 = IRO_NewENode(EINTCONST); + nd2->data.intval = field; + nd2->rtype = TYPE(&stunsignedlong); + + nd3 = IRO_NewENode(EADD); + nd3->data.diadic.left = nd; + nd3->data.diadic.right = nd2; + nd3->rtype = rtype; + + *resultNode = nd3; + } else { + *resultNode = nd; + } +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct LookupENodeExprActionParams { + Object *proc; + Type *indirectType; + ENodeList **list; +} LookupENodeExprActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void LookupENodeExprAction(LocationSet *loc, void *refcon) { + LookupENodeExprActionParams *params; + ENodeList *list; + + IRO_ASSERT(0, loc != NULL); + IRO_ASSERT(0, refcon != NULL); + + params = refcon; + + IRO_ASSERT(0, params->proc != NULL); + IRO_ASSERT(0, params->indirectType != NULL); + IRO_ASSERT(0, params->list != NULL); + + list = *params->list = IRO_malloc(sizeof(ENodeList)); + list->node = NULL; + list->next = NULL; + + if (!LocationSet_IsUnknown(loc) && LocationSetRepresentsSingleLocation(loc, NULL, NULL)) + CreateENodeForLocationSet(loc, &list->node, params->indirectType, params->proc); + + params->list = &list->next; +} + +void PointerAnalysis_LookupENodePointerExpr(Object *proc, ENode *indirect, ENodeList **list) { + LocationSetSet *set; + LookupENodeExprActionParams params; + + IRO_ASSERT(0, indirect != NULL); + + if (indirect->pointsTo) { + set = LocationSetSet_New(); + LocationSetSet_Init(set); + EvalENodeExpr(set, proc, indirect, NULL, NULL, NULL); + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.indirectType = indirect->rtype; + params.list = list; + + LocationSetSet_ForEach(set, LookupENodeExprAction, ¶ms); + LocationSetSet_Term(set); + LocationSetSet_Delete(set); + } +} + +void PointerAnalysis_LookupVariableIntoLinearNodeExprs(Object *proc, VarRecord *var, PointsToFunction *pointsTo, IROListNode **list) { + LocationSetSet *set; + LookupLinearExprActionParams params; + + if (pointsTo) { + set = LocationSetSet_New(); + LocationSetSet_Init(set); + EvalVariable(set, proc, var, pointsTo, NULL, NULL, NULL); + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.indirectType = var->object->type; + params.list = list; + + LocationSetSet_ForEach(set, LookupLinearExprAction, ¶ms); + LocationSetSet_Term(set); + LocationSetSet_Delete(set); + } +} + +void PointerAnalysis_LookupVariableIntoENodeExprs(Object *proc, VarRecord *var, PointsToFunction *pointsTo, ENodeList **list) { + LocationSetSet *set; + LookupENodeExprActionParams params; + + if (pointsTo) { + set = LocationSetSet_New(); + LocationSetSet_Init(set); + EvalVariable(set, proc, var, pointsTo, NULL, NULL, NULL); + + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.indirectType = var->object->type; + params.list = list; + + LocationSetSet_ForEach(set, LookupENodeExprAction, ¶ms); + LocationSetSet_Term(set); + LocationSetSet_Delete(set); + } +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct GetFunctionDepsOrKillsActionParams { + Object *proc; + PartialTransferFunction *ptf; + IROLinear *funccall; + ParamMappingFunction *map; + ObjectList **list; +} GetFunctionDepsOrKillsActionParams; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void GetFunctionDepsOrKillsAction(LocationSet *ls, void *refcon) { + GetFunctionDepsOrKillsActionParams *params; + ObjectList *list; + PAMemoryBlock *block; + ExtendedParam *ep; + ObjectSet *objSet; + PALocalVar *local; + Object *obj; + + IRO_ASSERT(7204, ls != NULL); + IRO_ASSERT(7205, refcon != NULL); + + params = refcon; + + IRO_ASSERT(7209, params->proc != NULL); + IRO_ASSERT(7210, params->ptf != NULL); + IRO_ASSERT(7211, params->funccall != NULL); + IRO_ASSERT(7212, params->map == NULL || params->map != NULL); + IRO_ASSERT(7213, params->list != NULL); + + list = *params->list = IRO_malloc(sizeof(ObjectList)); + list->object = NULL; + list->next = NULL; + + if (!LocationSet_IsUnknown(ls) && (block = LocationSet_block(ls))) { + obj = NULL; + switch (PAMemoryBlock_kind(block)) { + case PAMEMORYBLOCKKIND_EXTENDEDPARAM: + if ((ep = PAMemoryBlock_thing(block)) && (objSet = ExtendedParam_objectSet(ep))) { + IRO_ASSERT(7232, obj == NULL); + ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj); + } + break; + case PAMEMORYBLOCKKIND_LOCALVAR: + if ((local = PAMemoryBlock_thing(block))) { + obj = GetLocalObject(local, &stUnknown, 0); + if (ObjectIsAFunctionArgument(FunctionName, obj) && obj->u.var.realObj) + obj = obj->u.var.realObj; + } + break; + } + + list->object = obj; + } + + params->list = &list->next; +} + +static void GetFunctionDepsOrKillsAction2(PointsToEntry *pte, void *refcon) { + GetFunctionDepsOrKillsActionParams *params; + LocationSet *loc; + PAMemoryBlock *block; + LocationSetSet *set; + + IRO_ASSERT(7264, pte != NULL); + IRO_ASSERT(7265, refcon != NULL); + + params = refcon; + + IRO_ASSERT(7269, params->proc != NULL); + IRO_ASSERT(7270, params->ptf != NULL); + IRO_ASSERT(7271, params->funccall != NULL); + IRO_ASSERT(7272, params->map != NULL); + IRO_ASSERT(7273, params->list != NULL); + + loc = PointsToEntry_loc(pte); + + IRO_ASSERT(7277, !LocationSet_IsUnknown(loc)); + + if ((block = LocationSet_block(loc)) && PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) { + set = LocationSetSet_New(); + LocationSetSet_Init(set); + GetActualLocsOfExtendedParam(set, loc, NULL, &stCallingContextStack, params->map, 0); + LocationSetSet_ForEach(set, GetFunctionDepsOrKillsAction, params); + LocationSetSet_Term(set); + LocationSetSet_Delete(set); + } +} + +static void CreateFalseContext(Object *proc, IROLinear *funccall, PartialTransferFunction **resultPTF, ParamMappingFunction **resultMap) { + IROLinear myFunccall; + Boolean needVisit; + ParamMappingFunction *map; + PartialTransferFunction *ptf; + StackElement *stackElement; + ParamMappingFunction *map2; + PartialTransferFunction *ptf2; + StackElement *stackElement2; + + PointerAnalysis_Init(); + memset(&myFunccall, 0, sizeof(myFunccall)); + myFunccall.type = IROLinearFunccall; + + map = ParamMappingFunction_New(); + ParamMappingFunction_Init(map); + RecordActuals(&myFunccall, FunctionName, map); + + needVisit = 0; + ptf = GetPTF(map, FunctionName, &myFunccall, stUnknownPTF, &needVisit); + + stackElement = StackElement_New(); + StackElement_Init(stackElement, FunctionName, ptf, map, &myFunccall); + Stack_sub_48A660(&stCallingContextStack, stackElement); + StackElement_Term(stackElement); + StackElement_Delete(stackElement); + + map2 = ParamMappingFunction_New(); + ParamMappingFunction_Init(map2); + RecordActuals(funccall, proc, map2); + + if (FunctionName != proc) { + needVisit = 0; + ptf2 = GetPTF(map2, proc, funccall, ptf, &needVisit); + + stackElement2 = StackElement_New(); + StackElement_Init(stackElement2, proc, ptf2, map2, funccall); + Stack_sub_48A660(&stCallingContextStack, stackElement2); + StackElement_Term(stackElement2); + StackElement_Delete(stackElement2); + } else { + ptf2 = stUnknownPTF; + } + + *resultPTF = ptf2; + *resultMap = map2; +} + +static void DestroyFalseContext(Object *proc, PartialTransferFunction *ptf, ParamMappingFunction *map) { + StackElement *element; + + if (FunctionName != proc) { + element = Stack_sub_48A5B0(&stCallingContextStack); + StackElement_Term(element); + StackElement_Delete(element); + } + + ParamMappingFunction_Term(map); + ParamMappingFunction_Delete(map); + + element = Stack_sub_48A5B0(&stCallingContextStack); + map = StackElement_map(element); + ParamMappingFunction_Term(map); + ParamMappingFunction_Delete(map); + StackElement_Term(element); + StackElement_Delete(element); + + PointerAnalysis_Term(); +} + +void PointerAnalysis_GetFunctionKills(Object *proc, IROLinear *funccall, ObjectList **list) { + Boolean fail; + PartialTransferFunction *ptf; + LocationSetSet *set; + GetFunctionDepsOrKillsActionParams params; + + IRO_ASSERT(7398, proc != NULL); + IRO_ASSERT(7399, funccall != NULL); + IRO_ASSERT(7400, funccall->type == IROLinearFunccall); + + if (!ObjectIsAFunction(proc)) + return; + + fail = !proc->u.func.ptfList || !(ptf = PTFList_FindFirst(proc->u.func.ptfList)); + if (!fail) { + fail = !(set = PTF_sub_48D750(ptf)); + if (!fail) { + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.ptf = ptf; + params.funccall = funccall; + params.map = NULL; + params.list = list; + LocationSetSet_ForEach(set, GetFunctionDepsOrKillsAction, ¶ms); + } + } + + if (fail) { + *list = IRO_malloc(sizeof(ObjectList)); + (*list)->object = NULL; + (*list)->next = NULL; + } +} + +void PointerAnalysis_GetFunctionDependencies(Object *proc, IROLinear *funccall, ObjectList **list) { + Boolean fail; + PartialTransferFunction *ptf; + ParamMappingFunction *map; + PointsToFunction *finalPointsTo; + GetFunctionDepsOrKillsActionParams params; + + IRO_ASSERT(7446, proc != NULL); + IRO_ASSERT(7447, funccall != NULL); + IRO_ASSERT(7448, funccall->type == IROLinearFunccall); + + if (!ObjectIsAFunction(proc)) + return; + + fail = !proc->u.func.ptfList || !PTFList_FindFirst(proc->u.func.ptfList); + if (!fail) { + CreateFalseContext(proc, funccall, &ptf, &map); + fail = !ptf || !map || !(finalPointsTo = PartialTransferFunction_finalPointsToFn(ptf)); + if (!fail) { + memset(¶ms, 0, sizeof(params)); + params.proc = proc; + params.ptf = ptf; + params.funccall = funccall; + params.map = map; + params.list = list; + PointsToFunction_ForEach(finalPointsTo, GetFunctionDepsOrKillsAction2, ¶ms); + } + DestroyFalseContext(proc, ptf, map); + } + + if (fail) { + *list = IRO_malloc(sizeof(ObjectList)); + (*list)->object = NULL; + (*list)->next = NULL; + } +} + +void PointerAnalysis_PragmaMode(void) { + if (cparamblkptr->preprocess) { + skipendofline(); + return; + } + + if (notendofline()) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "addr")) { + copts.opt_pointer_analysis_mode = 0; + return; + } + if (!strcmp(tkidentifier->name, "ansi")) { + copts.opt_pointer_analysis_mode = 1; + return; + } + if (!strcmp(tkidentifier->name, "type")) { + copts.opt_pointer_analysis_mode = 2; + return; + } + } + + CPrep_Warning(CErrorStr105); + skipendofline(); + return; + } + + if (copts.warn_illpragma) + CPrep_Warning(CErrorStr186); + skipendofline(); +} + +typedef enum CreateNewParamObjects { + CREATE_NEW_PARAM_OBJECTS_FALSE, + CREATE_NEW_PARAM_OBJECTS_TRUE +} CreateNewParamObjects; + +static void ParseLocationSet(LocationSet *loc, Type *rtype, Object *proc, CreateNewParamObjects createNewParamObjects, Boolean arg5, int arg6, Boolean *arg7, Boolean *resultFailed) { + CInt64 field; + UInt32 stride; + PAMemoryBlock *block; + PAMemoryBlock *restriction; + Boolean failed; + Boolean flag37; + Boolean epFlag; + Boolean anotherFlag; + Boolean isUnknown; + + IRO_ASSERT(7552, loc != NULL); + IRO_ASSERT(7553, rtype == NULL || rtype != NULL); + IRO_ASSERT(7554, proc != NULL); + IRO_ASSERT(7555, createNewParamObjects == CREATE_NEW_PARAM_OBJECTS_FALSE || createNewParamObjects == CREATE_NEW_PARAM_OBJECTS_TRUE); + IRO_ASSERT(7556, resultFailed != NULL); + IRO_ASSERT(7557, *resultFailed == false); + IRO_ASSERT(7558, proc != NULL); + IRO_ASSERT(7559, proc == NULL || ObjectIsAFunction(proc)); + + failed = 0; + isUnknown = 0; + anotherFlag = 0; + field = cint64_zero; + stride = 0; + + tk = lex(); + if (tk == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "__unknown")) { + flag37 = 0; + isUnknown = 1; + tk = lookahead(); + if (tk == '(') { + lex(); + tk = lex(); + if (tk != TK_IDENTIFIER) { + CError_Error(CErrorStr107); + failed = 1; + } + if (!failed) { + PALocalVar *local; + local = PALocalVar_New(); + PALocalVar_InitByName(local, tkidentifier->name); + + block = PAMemoryBlock_New(); + PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_LOCALVAR, local); + + tk = lex(); + if (tk != ')') { + CError_Error(CErrorStr115); + failed = 1; + } + if (!failed) { + rtype = NULL; + restriction = block; + } + } + } else { + rtype = NULL; + restriction = NULL; + } + } else if (arg5 && !strcmp(tkidentifier->name, "__return_value")) { + flag37 = 0; + anotherFlag = 1; + } else if (!strcmp(tkidentifier->name, "__unique_heap_allocation")) { + PAHeapBlock *hb; + + flag37 = 0; + hb = CreateUniqueHeapAlloc_sub_486420(); + InitUniqueHeapAlloc_sub_486410(hb, NULL); + + block = PAMemoryBlock_New(); + PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_HEAPBLOCK, hb); + } else if (!strcmp(tkidentifier->name, "__parameter_representative")) { + flag37 = 1; + tk = lex(); + + if (tk == '(') { + tk = lex(); + if (tk != TK_INTCONST) { + CError_Error(CErrorStr121); + failed = 1; + } + if (!failed) { + Object *obj; + ObjectList *list; + ExtendedParam *ep; + obj = NULL; + for (list = stParamObjs; list; list = list->next) { + if ((obj = list->object) && (obj->u.var.uid == CInt64_GetULong(&tkintconst))) + break; + } + if (!list) + obj = NULL; + + if (!obj) { + if (createNewParamObjects) { + obj = IRO_malloc(sizeof(Object)); + memset(obj, 0, sizeof(Object)); + obj->datatype = DLOCAL; + obj->extParam = NULL; + obj->name = CParser_GetUniqueName(); + obj->type = TYPE(&stunsignedlong); + obj->qual = 0; + obj->u.var.info = NULL; + obj->u.var.uid = CInt64_GetULong(&tkintconst); + + list = IRO_malloc(sizeof(ObjectList)); + list->next = stParamObjs; + list->object = obj; + stParamObjs = list; + + ep = CreateExtendedParam(NULL, NULL, obj, &epFlag); + } else { + char buf[64]; + sprintf(buf, "__parameter_representative(%" PRId32 ")", obj->u.var.uid); + CError_Error(CErrorStr140, buf); + failed = 1; + } + } else { + ep = obj->extParam; + IRO_ASSERT(7687, ep != NULL); + } + + if (!failed) { + tk = lex(); + if (tk != ')') { + CError_Error(CErrorStr115); + failed = 1; + } + } + if (!failed) { + block = PAMemoryBlock_New(); + PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_EXTENDEDPARAM, ep); + } + } + } + } else { + Object *obj; + NameSpace *nspace; + + obj = NULL; + for (nspace = cscope_current; nspace; nspace = nspace->parent) { + NameSpaceObjectList *chk; + if ((chk = CScope_GetLocalObject(nspace, tkidentifier)) && chk->object->otype == OT_OBJECT) { + if (notendofline()) { + obj = OBJECT(chk->object); + break; + } + } + } + + if (!obj) { + ObjectList *chk; + for (chk = FunctionArguments(proc); chk; chk = chk->next) { + if (chk->object && chk->object->name && chk->object->name->name && !strcmp(tkidentifier->name, chk->object->name->name)) { + obj = chk->object; + } + } + } + + if (obj) { + PAMemoryBlockKind kind; + void *thing; + + if (ObjectIsAnExtendedParamCandidate(obj)) { + kind = PAMEMORYBLOCKKIND_EXTENDEDPARAM; + thing = CreateExtendedParam(NULL, NULL, obj, &epFlag); + } else { + kind = PAMEMORYBLOCKKIND_LOCALVAR; + thing = PALocalVar_New(); + if (obj->name && obj->name->name && ObjectIsAFunctionArgument(proc, obj)) + PALocalVar_InitByName(thing, obj->name->name); + else + PALocalVar_InitByObject(thing, obj); + } + + block = PAMemoryBlock_New(); + PAMemoryBlock_Init(block, kind, thing); + rtype = CDecl_NewPointerType(obj->type); + } else { + CError_Error(CErrorStr140, tkidentifier->name); + failed = 1; + } + } + } else if (tk == TK_INTCONST) { + flag37 = 0; + block = PAMemoryBlock_New(); + PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_INT, &tkintconst); + } else if (tk == '(') { + ParseLocationSet(loc, rtype, proc, createNewParamObjects, arg5, 1, &anotherFlag, &failed); + if (!failed) { + tk = plex(); + if (tk != ')') + CError_Error(CErrorStr115); + failed = 1; + } + } else { + CError_Error(CErrorStr121); + failed = 1; + } + + if (!failed && flag37) { + tk = lookahead(); + if (tk == '[') { + lex(); + if (rtype && IS_TYPE_POINTER(rtype) && IS_TYPE_POINTER(TPTR_TARGET(rtype))) { + tk = lex(); + if (tk == ']') { + if ((stride = rtype->size)) { + CInt64 tmp; + CInt64_SetLong(&tmp, stride); + field = CInt64_Mod(field, tmp); + } + rtype = TPTR_TARGET(rtype); + } else { + CError_Error(CErrorStr125); + } + } else { + CError_Error(CErrorStr148); + } + } else if (tk == '.') { + lex(); + if (rtype && IS_TYPE_POINTER(rtype) && IS_TYPE_STRUCT(TPTR_TARGET(rtype))) { + if (TPTR_TARGET(rtype)->size) { + tk = lex(); + if (tk == TK_IDENTIFIER) { + StructMember *member; + if ((member = ismember(TYPE_STRUCT(TPTR_TARGET(rtype)), tkidentifier))) { + CInt64_SetLong(&field, member->offset); + rtype = CDecl_NewPointerType(member->type); + } else { + CError_Error(CErrorStr150, tkidentifier); + } + } else { + CError_Error(CErrorStr107); + } + } else { + CError_Error(CErrorStr136, TPTR_TARGET(rtype), 0); + } + } else { + CError_Error(CErrorStr149); + } + } + } + + if (!failed && !anotherFlag) { + LocationSet_Term(loc); + if (!isUnknown) + LocationSet_InitKnown(loc, block, field, stride, rtype); + else + LocationSet_InitUnknown(loc, rtype, restriction, NULL); + } + + *arg7 = anotherFlag; + *resultFailed = failed; +} + +static void ParseLocationSetSet(LocationSetSet *locs, Type *rtype, Object *proc, CreateNewParamObjects createNewParamObjects, Boolean *resultFailed) { + Boolean failed; + + IRO_ASSERT(7892, locs != NULL); + IRO_ASSERT(7893, rtype == NULL || rtype != NULL); + IRO_ASSERT(7894, proc != NULL); + IRO_ASSERT(7895, createNewParamObjects == CREATE_NEW_PARAM_OBJECTS_FALSE || createNewParamObjects == CREATE_NEW_PARAM_OBJECTS_TRUE); + IRO_ASSERT(7896, resultFailed != NULL); + IRO_ASSERT(7897, *resultFailed == false); + IRO_ASSERT(7898, proc != NULL); + IRO_ASSERT(7899, proc == NULL || ObjectIsAFunction(proc)); + + failed = 0; + + tk = lex(); + if (tk != '(') { + CError_Error(CErrorStr114); + failed = 1; + } + + if (!failed) { + Boolean anotherFlag; + + LocationSet *ls; + ls = LocationSet_New(); + LocationSet_InitUnknown(ls, NULL, NULL, NULL); + + tk = lookahead(); + while (!failed && tk != ')') { + ParseLocationSet(ls, rtype, proc, createNewParamObjects, 0, 0, &anotherFlag, &failed); + if (!failed) + LocationSetSet_Add(locs, ls); + + if (!failed) { + tk = lookahead(); + if (tk == ',') { + lex(); + tk = lookahead(); + } else if (tk != ')') { + lex(); + CError_Error(CErrorStr121); + failed = 1; + } + } + } + + if (!failed) + lex(); + + LocationSet_Term(ls); + LocationSet_Delete(ls); + } + + *resultFailed = failed; +} + +static Object *GetFunctionObjectFromDeclInfo(DeclInfo *di) { + Object *proc; + + IRO_ASSERT(7953, di != NULL); + + if (di->storageclass != TK_TYPEDEF && IS_TYPE_FUNC(di->thetype)) { + Boolean flag; + proc = CDecl_GetFunctionObject(di, NULL, &flag, 1); + if (flag) + di->x64 = 1; + } else { + proc = NULL; + } + + return proc; +} + +void PointerAnalysis_ParseEntryPointsToSpecifier(DeclInfo *di) { + Object *proc; + Boolean failed; + Boolean anotherFlag; + + IRO_ASSERT(7982, di != NULL); + + proc = GetFunctionObjectFromDeclInfo(di); + if (proc) { + IRO_ASSERT(7987, proc == NULL || ObjectIsAFunction(proc)); + + tk = lex(); + IRO_ASSERT(7996, tk == TK_IDENTIFIER && strcmp(tkidentifier->name,"entry_points_to") == 0); + + failed = 0; + + tk = lex(); + if (tk != '(') { + CError_Error(CErrorStr114); + failed = 1; + } + + if (!failed) { + LocationSet *ls; + ls = LocationSet_New(); + LocationSet_InitUnknown(ls, NULL, NULL, NULL); + ParseLocationSet(ls, NULL, proc, CREATE_NEW_PARAM_OBJECTS_FALSE, 0, 0, &anotherFlag, &failed); + if (!failed) { + if ((tk = lex()) != ',') { + CError_Error(CErrorStr116); + failed = 1; + } + } + if (!failed) { + Type *type; + Type *innerType; + LocationSetSet *lss; + + type = LocationSet_rtype(ls); + if (type && IS_TYPE_POINTER(type)) + innerType = TPTR_TARGET(type); + else + innerType = NULL; + + lss = LocationSetSet_New(); + LocationSetSet_Init(lss); + ParseLocationSetSet(lss, innerType, proc, CREATE_NEW_PARAM_OBJECTS_TRUE, &failed); + if (!failed) { + if ((tk = lex()) != ')') { + CError_Error(CErrorStr115); + failed = 1; + } + } + if (!failed) { + PartialTransferFunction *ptf; + PointsToFunction *pointsToFunc; + PointsToEntry *pte; + + if (!proc->u.func.ptfList) { + proc->u.func.ptfList = PTFList_New(); + PTFList_Init(proc->u.func.ptfList); + } + ptf = PTFList_FindFirst(proc->u.func.ptfList); + if (!ptf) + ptf = AllocatePTF(proc, NULL, NULL); + + pointsToFunc = PartialTransferFunction_initialPointsToFn(ptf); + pte = PointsToEntry_New(); + PointsToEntry_Init(pte, ls, lss); + PointsToFunction_Add(pointsToFunc, pte); + PointsToEntry_Term(pte); + PointsToEntry_Delete(pte); + } + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + } + LocationSet_Term(ls); + LocationSet_Delete(ls); + } + } +} + +void PointerAnalysis_ParseExitPointsToSpecifier(DeclInfo *di) { + Object *proc; + Boolean failed; + Boolean anotherFlag; + + IRO_ASSERT(8097, di != NULL); + + proc = GetFunctionObjectFromDeclInfo(di); + if (proc) { + IRO_ASSERT(8102, proc == NULL || ObjectIsAFunction(proc)); + + tk = lex(); + IRO_ASSERT(8111, tk == TK_IDENTIFIER && strcmp(tkidentifier->name,"exit_points_to") == 0); + + failed = 0; + + tk = lex(); + if (tk != '(') { + CError_Error(CErrorStr114); + failed = 1; + } + + if (!failed) { + LocationSet *ls; + ls = LocationSet_New(); + LocationSet_InitUnknown(ls, NULL, NULL, NULL); + ParseLocationSet(ls, NULL, proc, CREATE_NEW_PARAM_OBJECTS_FALSE, 1, 0, &anotherFlag, &failed); + if (!failed) { + if ((tk = lex()) != ',') { + CError_Error(CErrorStr116); + failed = 1; + } + } + if (!failed) { + Type *type; + Type *innerType; + LocationSetSet *lss; + + type = LocationSet_rtype(ls); + if (type && IS_TYPE_POINTER(type)) + innerType = TPTR_TARGET(type); + else + innerType = NULL; + + lss = LocationSetSet_New(); + LocationSetSet_Init(lss); + ParseLocationSetSet(lss, innerType, proc, CREATE_NEW_PARAM_OBJECTS_FALSE, &failed); + if (!failed) { + if ((tk = lex()) != ')') { + CError_Error(CErrorStr115); + failed = 1; + } + } + if (!failed) { + PartialTransferFunction *ptf; + PointsToFunction *pointsToFunc; + PointsToEntry *pte; + + if (!proc->u.func.ptfList) { + proc->u.func.ptfList = PTFList_New(); + PTFList_Init(proc->u.func.ptfList); + } + ptf = PTFList_FindFirst(proc->u.func.ptfList); + if (!ptf) + ptf = AllocatePTF(proc, NULL, NULL); + + pointsToFunc = PartialTransferFunction_finalPointsToFn(ptf); + pte = PointsToEntry_New(); + if (anotherFlag) + PointsToEntry_Init(pte, PartialTransferFunction_returnLocation(ptf), lss); + else + PointsToEntry_Init(pte, ls, lss); + PointsToFunction_Add(pointsToFunc, pte); + PointsToEntry_Term(pte); + PointsToEntry_Delete(pte); + } + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + } + LocationSet_Term(ls); + LocationSet_Delete(ls); + } + } +} + +void PointerAnalysis_ParseFunctionModifiesSpecifier(DeclInfo *di) { + Object *proc; + Boolean failed; + LocationSetSet *lss; + PartialTransferFunction *ptf; + LocationSetSet *ptfLSS; + + IRO_ASSERT(8211, di != NULL); + + proc = GetFunctionObjectFromDeclInfo(di); + if (proc) { + IRO_ASSERT(8216, proc == NULL || ObjectIsAFunction(proc)); + + tk = lex(); + IRO_ASSERT(8225, tk == TK_IDENTIFIER && strcmp(tkidentifier->name,"function_modifies") == 0); + + failed = 0; + lss = LocationSetSet_New(); + LocationSetSet_Init(lss); + ParseLocationSetSet(lss, NULL, proc, CREATE_NEW_PARAM_OBJECTS_FALSE, &failed); + if (!failed) { + if (!proc->u.func.ptfList) { + proc->u.func.ptfList = PTFList_New(); + PTFList_Init(proc->u.func.ptfList); + } + ptf = PTFList_FindFirst(proc->u.func.ptfList); + if (!ptf) + ptf = AllocatePTF(proc, NULL, NULL); + ptfLSS = PTF_sub_48D750(ptf); + LocationSetSet_RemoveAll(ptfLSS); + LocationSetSet_AddSet(ptfLSS, lss); + } + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + } +} + diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.h b/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.h new file mode 100644 index 0000000..ec50eba --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.h @@ -0,0 +1,25 @@ +#ifndef COMPILER_IROPOINTERANALYSIS_H +#define COMPILER_IROPOINTERANALYSIS_H + +#include "IrOptimizer.h" + +extern void PointerAnalysis_Setup(void); +extern void PointerAnalysis_Cleanup(void); +extern void IRO_AnalyzePointers(Object *function); +extern Boolean PointerAnalysis_TwoLinearNodePointerExprsMightAlias(Object *proc, IROLinear *nd1, IROLinear *nd2); +extern Boolean PointerAnalysis_TwoENodePointerExprsMightAlias(Object *proc, ENode *nd1, ENode *nd2); +extern Boolean PointerAnalysis_IsLinearNodePointerExprDefinite(Object *proc, IROLinear *nd); +extern Boolean PointerAnalysis_IsENodePointerExprDefinite(Object *proc, ENode *nd); +extern Boolean PointerAnalysis_IsVariableValueDefinite(Object *proc, VarRecord *var, PointsToFunction *pointsTo); +extern void PointerAnalysis_LookupLinearNodePointerExpr(Object *proc, IROLinear *indirect, IROListNode **list); +extern void PointerAnalysis_LookupENodePointerExpr(Object *proc, ENode *indirect, ENodeList **list); +extern void PointerAnalysis_LookupVariableIntoLinearNodeExprs(Object *proc, VarRecord *var, PointsToFunction *pointsTo, IROListNode **list); +extern void PointerAnalysis_LookupVariableIntoENodeExprs(Object *proc, VarRecord *var, PointsToFunction *pointsTo, ENodeList **list); +extern void PointerAnalysis_GetFunctionKills(Object *proc, IROLinear *funccall, ObjectList **list); +extern void PointerAnalysis_GetFunctionDependencies(Object *proc, IROLinear *funccall, ObjectList **list); +extern void PointerAnalysis_PragmaMode(void); +extern void PointerAnalysis_ParseEntryPointsToSpecifier(DeclInfo *di); +extern void PointerAnalysis_ParseExitPointsToSpecifier(DeclInfo *di); +extern void PointerAnalysis_ParseFunctionModifiesSpecifier(DeclInfo *di); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysisADTs.c b/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysisADTs.c new file mode 100644 index 0000000..dad9501 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysisADTs.c @@ -0,0 +1,2736 @@ +#include "IroPointerAnalysis.h" +#include "IroMalloc.h" +#include "compiler/CError.h" +#include "compiler/CInt64.h" +#include "compiler/CParser.h" +#include "compiler/objects.h" +#include "compiler/types.h" + +// TODO: this should really be elsewhere (but where?) +CW_INLINE UInt32 gcd(UInt32 a, UInt32 b) { + UInt32 chk; + + if (!a) + return b; + if (!b) + return a; + + while (1) { + chk = a % b; + if (!chk) + return b; + a = b; + b = chk; + } +} + +// #define IRO_DEBUG + +typedef struct ExtendedParamSet ExtendedParamSet; +typedef struct LocationSet LocationSet; +typedef struct LocationSetSet LocationSetSet; +typedef struct ObjectSet ObjectSet; +typedef struct PAHeapBlock PAHeapBlock; +typedef struct PALocalVar PALocalVar; +typedef struct PAMemoryBlock PAMemoryBlock; +typedef struct ParamMapping ParamMapping; +typedef struct ParamMappingFunction ParamMappingFunction; +typedef struct PartialTransferFunction PartialTransferFunction; +typedef struct PointsToEntry PointsToEntry; +// typedef struct PointsToFunction PointsToFunction; +typedef struct Stack Stack; +typedef struct StackElement StackElement; + +typedef UInt32 uint32; + +void __assertion_failed(char *expr, char *filename, int line); + +#ifdef IRO_DEBUG +#define IRO_ASSERT(line, expr) \ + do { \ + if (!(expr)) { \ + __assertion_failed(#expr, __FILE__, line); \ + } \ + } while (0); + +#define IRO_DEBUG_CLEAR(obj, type) \ + memset((obj), 0xFF, sizeof(type)) +#else +#define IRO_ASSERT(line, expr) ((void) 0) +#define IRO_DEBUG_CLEAR(obj, type) ((void) 0) +#endif + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +struct StackElement { + Object *proc; + PartialTransferFunction *ptf; + ParamMappingFunction *map; + IROLinear *funcCall; +}; + +struct Stack { + StackElement *top; + Stack *next; +}; + +struct ObjectSet { + Object *proc; + ObjectSet *otherProcs; +}; + +struct ExtendedParam { + ObjectSet *objectSet; + uint32 x4; +}; + +struct ExtendedParamSet { + ExtendedParam *ep; + ExtendedParamSet *otherEps; +}; + +struct PAHeapBlock { + IROLinear *x0; +}; + +struct PALocalVar { + Object *x0; + char *x4; +}; + +typedef enum { + PAMEMORYBLOCKKIND_INVALID, + PAMEMORYBLOCKKIND_1, + PAMEMORYBLOCKKIND_EXTENDEDPARAM, + PAMEMORYBLOCKKIND_LOCALVAR, + PAMEMORYBLOCKKIND_HEAPBLOCK, + PAMEMORYBLOCKKIND_INT, + PAMEMORYBLOCKKIND_6 +} PAMemoryBlockKind; + +struct PAMemoryBlock { + PAMemoryBlockKind kind; + union { + ExtendedParam *ep; + PALocalVar *localvar; + PAHeapBlock *heapblock; + CInt64 intval; + void *x6; + } u; +}; + +struct LocationSet { + PAMemoryBlock *block; + Type *rtype; + union { + struct { + CInt64 field; + UInt32 stride; + } known; + struct { + PAMemoryBlock *restriction; + LocationSet *bitfieldOf; + } unknown; + } u; +}; + +struct LocationSetSet { + LocationSet *loc; + LocationSetSet *otherLocs; + UInt8 count; +}; + +struct ParamMapping { + IROLinear *actual; + Object *formal; + ExtendedParam *extended; +}; + +struct ParamMappingFunction { + ParamMapping *mapping; + ParamMappingFunction *otherMappings; +}; + +struct PointsToEntry { + LocationSet *loc; + LocationSetSet *locs; +}; + +struct PointsToFunction { + PointsToEntry *pte; + PointsToFunction *otherPtes; +}; + +struct PartialTransferFunction { + PointsToFunction *initialPointsToFn; + PointsToFunction *finalPointsToFn; + LocationSetSet *funcModifies; + LocationSet *returnLocation; + Boolean x10; + struct { + IROLinear *nd; + PartialTransferFunction *ptf; + } context; +}; + +struct PTFList { + PartialTransferFunction *ptf; + PTFList *otherPTFs; +}; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +// TODO: how many of these are actually in IroPointerAnalysis.c? +static uint32 stExtendedParamNum; +static PartialTransferFunction *stUnknownPTF; +static uint32 stIndentationLevel; +static UInt8 stTabs[0x2C]; // unused mystery object +static Stack *stCallingContextStack; +static ObjectList *stParamObjs; +static jmp_buf stAbortPointerAnalysis; +static Object stUnknown; +static Object *stCurrentProc; +static ExtendedParamSet *stExtParamSet; +static PTFList *stPTFList; +static uint32 stMaxPassCount; +// TODO: stEvalProcActionParams +static IRONode *stExceptionFNode; + +static PAMemoryBlock stDummyMemoryBlock = { + PAMEMORYBLOCKKIND_1 +}; +static PAMemoryBlock *stUnknownMb = &stDummyMemoryBlock; + +static LocationSet stDummyLocationSet = { + &stDummyMemoryBlock +}; + +static LocationSet *stUnknownLs = &stDummyLocationSet; + +// forward decls +CW_INLINE StackElement *Stack_sub_48A5B0(Stack **stackPtr); +CW_INLINE void ObjectSet_RemoveAll(ObjectSet *procList); +CW_INLINE void ExtendedParamSet_RemoveAll(ExtendedParamSet *epList); +CW_INLINE void LocationSet_Copy(LocationSet *dest, LocationSet *src); +CW_INLINE Boolean LocationSet_IsUnknown(LocationSet *ls); +CW_INLINE void LocationSetSet_RemoveAll(LocationSetSet *lss); +CW_INLINE void LocationSetSet_AddSet(LocationSetSet *dest, LocationSetSet *src); +CW_INLINE void ParamMappingFunction_RemoveAll(ParamMappingFunction *pmf); +CW_INLINE void ParamMappingFunction_AddAllMaybe_sub_487C50(ParamMappingFunction *dest, ParamMappingFunction *src); +CW_INLINE void PointsToFunction_RemoveAll(PointsToFunction *pointsToFunc); +CW_INLINE void PointsToFunction_AddAllIGuess_sub_487D80(PointsToFunction *dest, PointsToFunction *src); +CW_INLINE void PTFList_RemoveAll(PTFList *ptfList); + +CW_INLINE StackElement *StackElement_New(void) { + StackElement *stackElement = IRO_malloc(sizeof(StackElement)); + IRO_ASSERT(103, stackElement != NULL); +#ifdef IRO_DEBUG + stackElement->proc = NULL; + stackElement->ptf = NULL; + stackElement->map = NULL; + stackElement->funcCall = NULL; +#endif + return stackElement; +} + +CW_INLINE void StackElement_Delete(StackElement *stackElement) { + IRO_ASSERT(117, stackElement != NULL); + IRO_ASSERT(118, stackElement->proc == NULL); + IRO_ASSERT(119, stackElement->ptf == NULL); + IRO_ASSERT(120, stackElement->map == NULL); + IRO_ASSERT(121, stackElement->funcCall == NULL); + IRO_DEBUG_CLEAR(stackElement, sizeof(StackElement)); + IRO_free(stackElement); +} + +CW_INLINE void StackElement_Init(StackElement *stackElement, Object *proc, PartialTransferFunction *ptf, ParamMappingFunction *map, IROLinear *funcCall) { + IRO_ASSERT(131, stackElement != NULL); + IRO_ASSERT(132, proc != NULL); + IRO_ASSERT(133, ptf != NULL); + IRO_ASSERT(134, map != NULL); + IRO_ASSERT(135, funcCall != NULL); + stackElement->proc = proc; + stackElement->ptf = ptf; + stackElement->map = map; + stackElement->funcCall = funcCall; +} + +CW_INLINE void StackElement_Copy(StackElement *dest, StackElement *src) { + IRO_ASSERT(145, dest != NULL); + IRO_ASSERT(146, src != NULL); + StackElement_Init(dest, src->proc, src->ptf, src->map, src->funcCall); +} + +CW_INLINE void StackElement_Term(StackElement *stackElement) { + IRO_ASSERT(156, stackElement != NULL); +#ifdef IRO_DEBUG + stackElement->proc = NULL; + stackElement->ptf = NULL; + stackElement->map = NULL; + stackElement->funcCall = NULL; +#endif +} + +CW_INLINE void *StackElement_sub_48A780(StackElement *stackElement) { + IRO_ASSERT(213, stackElement != NULL); + return stackElement->proc; +} + +CW_INLINE Boolean StackRelated_sub_48A760(void *key1, void *key2) { + IRO_ASSERT(220, key1 != NULL); + IRO_ASSERT(221, key2 != NULL); + return key1 == key2; +} + +CW_INLINE Object *StackElement_proc(StackElement *stackElement) { + IRO_ASSERT(228, stackElement != NULL); + return stackElement->proc; +} + +CW_INLINE PartialTransferFunction *StackElement_ptf(StackElement *stackElement) { + IRO_ASSERT(235, stackElement != NULL); + return stackElement->ptf; +} + +CW_INLINE ParamMappingFunction *StackElement_map(StackElement *stackElement) { + IRO_ASSERT(242, stackElement != NULL); + return stackElement->map; +} + +CW_INLINE IROLinear *StackElement_funcCall(StackElement *stackElement) { + IRO_ASSERT(249, stackElement != NULL); + return stackElement->funcCall; +} + +CW_INLINE Stack *Stack_New(void) { + Stack *stack = IRO_malloc(sizeof(Stack)); + IRO_ASSERT(265, stack != NULL); +#ifdef IRO_DEBUG + stack->top = NULL; + stack->next = NULL; +#endif + return stack; +} + +CW_INLINE void Stack_Delete(Stack *stack) { + IRO_ASSERT(277, stack != NULL); + IRO_ASSERT(278, stack->top == NULL); + IRO_ASSERT(279, stack->next == NULL); + IRO_DEBUG_CLEAR(stack, sizeof(Stack)); + IRO_free(stack); +} + +CW_INLINE void Stack_Init(Stack *stack) { + IRO_ASSERT(289, stack != NULL); + stack->top = NULL; + stack->next = NULL; +} + +CW_INLINE void Stack_Term(Stack **stackPtr) { + StackElement *stackElement; + + IRO_ASSERT(299, stackPtr != NULL); + IRO_ASSERT(300, *stackPtr != NULL); + + while ((*stackPtr)->top) { + stackElement = Stack_sub_48A5B0(stackPtr); + StackElement_Term(stackElement); + StackElement_Delete(stackElement); + } +} + +CW_INLINE void Stack_sub_48A660(Stack **stackPtr, StackElement *stackElement) { + StackElement *newElement; + Stack *newStack; + + IRO_ASSERT(315, stackPtr != NULL); + IRO_ASSERT(316, *stackPtr != NULL); + + newElement = StackElement_New(); + StackElement_Copy(newElement, stackElement); + + newStack = Stack_New(); + newStack->top = newElement; + newStack->next = *stackPtr; + *stackPtr = newStack; +} + +CW_INLINE StackElement *Stack_Top(Stack **stackPtr) { + IRO_ASSERT(331, stackPtr != NULL); + IRO_ASSERT(332, *stackPtr != NULL); + + return (*stackPtr)->top; +} + +CW_INLINE Stack *Stack_Next(Stack **stackPtr) { + IRO_ASSERT(343, stackPtr != NULL); + IRO_ASSERT(344, *stackPtr != NULL); + + return (*stackPtr)->next; +} + +CW_INLINE StackElement *Stack_sub_48A5B0(Stack **stackPtr) { + StackElement *stackElement; + + IRO_ASSERT(357, stackPtr != NULL); + IRO_ASSERT(358, *stackPtr != NULL); + + stackElement = (*stackPtr)->top; + if (stackElement) { + Stack *next = (*stackPtr)->next; + (*stackPtr)->top = NULL; + (*stackPtr)->next = NULL; + Stack_Delete(*stackPtr); + *stackPtr = next; + } + + return stackElement; +} + +CW_INLINE StackElement *Stack_sub_48A710(Stack **stackPtr, void *key) { + Stack *stack; + + IRO_ASSERT(379, stackPtr != NULL); + IRO_ASSERT(380, key != NULL); + + for (stack = *stackPtr; stack; stack = stack->next) { + if (stack->top) { + if (StackRelated_sub_48A760(StackElement_sub_48A780(stack->top), key)) + return stack->top; + } + } + + return NULL; +} + +CW_INLINE ObjectSet *ObjectSet_New(void) { + ObjectSet *procList; + + procList = IRO_malloc(sizeof(ObjectSet)); + IRO_ASSERT(439, procList != NULL); +#ifdef IRO_DEBUG + procList->proc = NULL; + procList->otherProcs = NULL; +#endif + return procList; +} + +CW_INLINE void ObjectSet_Delete(ObjectSet *procList) { + IRO_ASSERT(451, procList != NULL); + IRO_ASSERT(452, procList->proc == NULL); + IRO_ASSERT(453, procList->otherProcs == NULL); + IRO_DEBUG_CLEAR(procList, sizeof(ObjectSet)); + IRO_free(procList); +} + +CW_INLINE void ObjectSet_Init(ObjectSet *procList) { + IRO_ASSERT(463, procList != NULL); + procList->proc = NULL; + procList->otherProcs = NULL; +} + +CW_INLINE void ObjectSet_Term(ObjectSet *procList) { + IRO_ASSERT(481, procList != NULL); + ObjectSet_RemoveAll(procList); +#ifdef IRO_DEBUG + procList->proc = NULL; + procList->otherProcs = NULL; +#endif +} + +CW_INLINE void ObjectSet_ForEach(ObjectSet *procList, void (*action)(Object *, void *), void *refcon) { + IRO_ASSERT(528, procList != NULL); + IRO_ASSERT(529, action != NULL); + IRO_ASSERT(530, refcon == NULL || refcon != NULL); + + while (procList && procList->proc) { + action(procList->proc, refcon); + procList = procList->otherProcs; + } +} + +CW_INLINE Object *ObjectSet_sub_485020(ObjectSet *procList, Object *proc) { + IRO_ASSERT(540, procList != NULL); + IRO_ASSERT(541, proc != NULL); + while (procList && procList->proc) { + if (procList->proc == proc) + return procList->proc; + procList = procList->otherProcs; + } + return NULL; +} + +CW_INLINE Object *ObjectSet_FindFirst(ObjectSet *procList) { + IRO_ASSERT(552, procList != NULL); + return procList->proc; +} + +CW_INLINE int ObjectSet_Count(ObjectSet *procList) { + int count; + + IRO_ASSERT(561, procList != NULL); + + count = 0; + while (procList && procList->proc) { + count++; + procList = procList->otherProcs; + } + + return count; +} + +CW_INLINE void ObjectSet_sub_486800(ObjectSet *procList, Object *proc) { + ObjectSet *newProcList; + + IRO_ASSERT(574, procList != NULL); + IRO_ASSERT(575, proc != NULL); + + if (procList->proc) { + newProcList = ObjectSet_New(); + ObjectSet_Init(newProcList); + newProcList->proc = procList->proc; + newProcList->otherProcs = procList->otherProcs; + procList->otherProcs = newProcList; + } + + procList->proc = proc; +} + +CW_INLINE void ObjectSet_sub_4867D0(ObjectSet *procList, Object *proc) { + IRO_ASSERT(592, procList != NULL); + IRO_ASSERT(593, proc != NULL); + + if (!ObjectSet_sub_485020(procList, proc)) + ObjectSet_sub_486800(procList, proc); +} + +CW_INLINE void ObjectSet_Remove(ObjectSet *procList, Object *proc) { + ObjectSet *prev; + ObjectSet *tmp; + + IRO_ASSERT(605, procList != NULL); + IRO_ASSERT(606, proc != NULL); + + prev = NULL; + while (procList && procList->proc) { + if (procList->proc == proc) { + if (!prev) { + if (procList->otherProcs == NULL) { + procList->proc = NULL; + } else { + tmp = procList->otherProcs; + procList->proc = procList->otherProcs->proc; + procList->otherProcs = procList->otherProcs->otherProcs; + tmp->proc = NULL; + tmp->otherProcs = NULL; + ObjectSet_Term(tmp); + ObjectSet_Delete(tmp); + } + } else { + prev->otherProcs = procList->otherProcs; + procList->proc = NULL; + procList->otherProcs = NULL; + ObjectSet_Term(procList); + ObjectSet_Delete(procList); + } + return; + } + prev = procList; + procList = procList->otherProcs; + } +} + +CW_INLINE void ObjectSet_RemoveAll(ObjectSet *procList) { + IRO_ASSERT(645, procList != NULL); + + while (procList && procList->proc) + ObjectSet_Remove(procList, procList->proc); +} + +CW_INLINE void ObjectSet_AddSetAction(Object *proc, void *refcon) { + IRO_ASSERT(655, proc != NULL); + IRO_ASSERT(656, refcon != NULL); + + ObjectSet_sub_4867D0(refcon, proc); +} + +CW_INLINE void ObjectSet_SimpleAddSetAction(Object *proc, void *refcon) { + IRO_ASSERT(663, proc != NULL); + IRO_ASSERT(664, refcon != NULL); + + ObjectSet_sub_486800(refcon, proc); +} + +CW_INLINE void ObjectSet_sub_48C590(ObjectSet *dest, ObjectSet *src) { + IRO_ASSERT(671, dest != NULL); + IRO_ASSERT(672, src != NULL); + + if (dest->proc) + ObjectSet_ForEach(src, ObjectSet_AddSetAction, dest); + else + ObjectSet_ForEach(src, ObjectSet_SimpleAddSetAction, dest); +} + +CW_INLINE void ObjectSet_RemoveSetAction(Object *proc, void *refcon) { + IRO_ASSERT(682, proc != NULL); + IRO_ASSERT(683, refcon != NULL); + + ObjectSet_Remove(refcon, proc); +} + +CW_INLINE void ObjectSet_removeiter_sub_48C890(ObjectSet *dest, ObjectSet *src) { + IRO_ASSERT(690, dest != NULL); + IRO_ASSERT(691, src != NULL); + + ObjectSet_ForEach(src, ObjectSet_RemoveSetAction, dest); +} + +CW_INLINE Boolean ObjectSet_sub_484FA0(ObjectSet *os1, ObjectSet *os2) { + ObjectSet *scan; + + IRO_ASSERT(700, os1 != NULL); + IRO_ASSERT(701, os2 != NULL); + + if (os1 == os2) + return 1; + + for (scan = os1; scan && scan->proc; scan = scan->otherProcs) { + if (!ObjectSet_sub_485020(os2, scan->proc)) + return 0; + } + + for (scan = os2; scan && scan->proc; scan = scan->otherProcs) { + if (!ObjectSet_sub_485020(os1, scan->proc)) + return 0; + } + + return 1; +} + +CW_INLINE ExtendedParam *ExtendedParam_New(void) { + ExtendedParam *ep = IRO_malloc(sizeof(ExtendedParam)); + + IRO_ASSERT(755, ep != NULL); +#ifdef IRO_DEBUG + ep->objectSet = NULL; +#endif + return ep; +} + +CW_INLINE void ExtendedParam_Delete(ExtendedParam *ep) { + IRO_ASSERT(762, ep != NULL); + IRO_ASSERT(763, ep->objectSet == NULL); + IRO_DEBUG_CLEAR(ep, sizeof(ExtendedParam)); + IRO_free(ep); +} + +CW_INLINE void ExtendedParam_Init(ExtendedParam *ep, Object *obj) { + IRO_ASSERT(777, ep != NULL); + IRO_ASSERT(778, obj != NULL); + IRO_ASSERT(779, obj->extParam == NULL); + IRO_ASSERT(780, stExtendedParamNum < ((uint32) -1) / 2 - 1); + + ep->objectSet = ObjectSet_New(); + ObjectSet_Init(ep->objectSet); + ObjectSet_sub_4867D0(ep->objectSet, obj); + obj->extParam = ep; + + ep->x4 = stExtendedParamNum++; +} + +CW_INLINE void ExtendedParam_TermAction(Object *obj, void *refcon) { + obj->extParam = NULL; +} + +CW_INLINE void ExtendedParam_Term(ExtendedParam *ep) { + IRO_ASSERT(800, ep != NULL); + + ObjectSet_ForEach(ep->objectSet, ExtendedParam_TermAction, NULL); + ObjectSet_Term(ep->objectSet); + ObjectSet_Delete(ep->objectSet); +#ifdef IRO_DEBUG + ep->objectSet = NULL; +#endif +} + +CW_INLINE Boolean ExtendedParams_Equal(ExtendedParam *ep1, ExtendedParam *ep2) { + IRO_ASSERT(841, ep1 != NULL); + IRO_ASSERT(842, ep2 != NULL); + IRO_ASSERT(843, ep1->objectSet != NULL); + IRO_ASSERT(844, ep2->objectSet != NULL); + + if (ep1 == ep2) + return 1; + + return ep1->x4 == ep2->x4 && ObjectSet_sub_484FA0(ep1->objectSet, ep2->objectSet); +} + +CW_INLINE ExtendedParam *ExtendedParam_FindByObject(Object *obj) { + IRO_ASSERT(856, obj != NULL); + + return obj->extParam; +} + +CW_INLINE void ExtendedParam_sub_4867B0(ExtendedParam *ep, Object *obj) { + IRO_ASSERT(863, ep != NULL); + IRO_ASSERT(864, ep->objectSet != NULL); + IRO_ASSERT(865, obj != NULL); + + ObjectSet_sub_4867D0(ep->objectSet, obj); + obj->extParam = ep; +} + +CW_INLINE void ExtendedParam_RemoveObjectSetAction(Object *object, void *refcon) { + object->extParam = NULL; +} + +CW_INLINE void EP_sub_48C850(ExtendedParam *ep, ObjectSet *objSet) { + IRO_ASSERT(888, ep != NULL); + IRO_ASSERT(889, ep->objectSet != NULL); + IRO_ASSERT(890, objSet != NULL); + + ObjectSet_removeiter_sub_48C890(ep->objectSet, objSet); + ObjectSet_ForEach(objSet, ExtendedParam_RemoveObjectSetAction, NULL); +} + +CW_INLINE ObjectSet *ExtendedParam_objectSet(ExtendedParam *ep) { + IRO_ASSERT(898, ep != NULL); + + return ep->objectSet; +} + +CW_INLINE uint32 ExtendedParam_sub_489110(ExtendedParam *ep) { + IRO_ASSERT(905, ep != NULL); + + return ep->x4; +} + +CW_INLINE ExtendedParamSet *AllocsExtParamSet_sub_4876C0(void) { + ExtendedParamSet *epList = IRO_malloc(sizeof(ExtendedParamSet)); + + IRO_ASSERT(924, epList != NULL); +#ifdef IRO_DEBUG + epList->ep = NULL; + epList->otherEps = NULL; +#endif + return epList; +} + +CW_INLINE void FreesExtParamSet_sub_48CAE0(ExtendedParamSet *epList) { + IRO_ASSERT(936, epList != NULL); + IRO_ASSERT(937, epList->ep == NULL); + IRO_ASSERT(938, epList->otherEps == NULL); + IRO_DEBUG_CLEAR(epList, sizeof(ExtendedParamSet)); + IRO_free(epList); +} + +CW_INLINE void InitsExtParamSet_sub_4876A0(ExtendedParamSet *epList) { + IRO_ASSERT(948, epList != NULL); + epList->ep = NULL; + epList->otherEps = NULL; +} + +CW_INLINE void TermsExtParamSet_sub_48CB00(ExtendedParamSet *epList) { + IRO_ASSERT(966, epList != NULL); + ExtendedParamSet_RemoveAll(epList); +#ifdef IRO_DEBUG + epList->ep = NULL; + epList->otherEps = NULL; +#endif +} + +CW_INLINE void MaybeWalkExtParamSet_sub_48CBE0(ExtendedParamSet *epList, void (*action)(ExtendedParam *, void *), void *refcon) { + IRO_ASSERT(1010, epList != NULL); + IRO_ASSERT(1011, action != NULL); + + while (epList && epList->ep) { + action(epList->ep, refcon); + epList = epList->otherEps; + } +} + +CW_INLINE ExtendedParam *ExtParamSet_sub_4876D0(ExtendedParamSet *epList, ExtendedParam *ep) { + IRO_ASSERT(1022, epList != NULL); + IRO_ASSERT(1023, ep != NULL); + + while (epList && epList->ep) { + if (epList->ep == ep) + return epList->ep; + epList = epList->otherEps; + } + + return NULL; +} + +CW_INLINE void ExtParamSet_sub_487660(ExtendedParamSet *epList, ExtendedParam *ep) { + IRO_ASSERT(1056, epList != NULL); + IRO_ASSERT(1057, ep != NULL); + + if (epList->ep) { + ExtendedParamSet *newSet = AllocsExtParamSet_sub_4876C0(); + InitsExtParamSet_sub_4876A0(newSet); + newSet->ep = epList->ep; + newSet->otherEps = epList->otherEps; + epList->otherEps = newSet; + } + + epList->ep = ep; +} + +CW_INLINE void ExtParamSet_sub_487630(ExtendedParamSet *epList, ExtendedParam *ep) { + IRO_ASSERT(1076, epList != NULL); + IRO_ASSERT(1077, ep != NULL); + + if (!ExtParamSet_sub_4876D0(epList, ep)) + ExtParamSet_sub_487660(epList, ep); +} + +CW_INLINE void ExtendedParamSet_Remove(ExtendedParamSet *epList, ExtendedParam *ep) { + ExtendedParamSet *prev; + ExtendedParamSet *tmp; + + IRO_ASSERT(1089, epList != NULL); + IRO_ASSERT(1090, ep != NULL); + + prev = NULL; + while (epList && epList->ep) { + if (epList->ep == ep) { + if (!prev) { + if (epList->otherEps == NULL) { + epList->ep = NULL; + } else { + tmp = epList->otherEps; + epList->ep = epList->otherEps->ep; + epList->otherEps = epList->otherEps->otherEps; + tmp->ep = NULL; + tmp->otherEps = NULL; + TermsExtParamSet_sub_48CB00(tmp); + FreesExtParamSet_sub_48CAE0(tmp); + } + } else { + prev->otherEps = epList->otherEps; + epList->ep = NULL; + epList->otherEps = NULL; + TermsExtParamSet_sub_48CB00(epList); + FreesExtParamSet_sub_48CAE0(epList); + } + return; + } + prev = epList; + epList = epList->otherEps; + } +} + +CW_INLINE void ExtendedParamSet_RemoveAll(ExtendedParamSet *epList) { + IRO_ASSERT(1129, epList != NULL); + + while (epList && epList->ep) + ExtendedParamSet_Remove(epList, epList->ep); +} + +CW_INLINE PAHeapBlock *CreateUniqueHeapAlloc_sub_486420(void) { + PAHeapBlock *hb = IRO_malloc(sizeof(PAHeapBlock)); + + IRO_ASSERT(1225, hb != NULL); +#ifdef IRO_DEBUG + hb->parent = NULL; +#endif + return hb; +} + +CW_INLINE void InitUniqueHeapAlloc_sub_486410(PAHeapBlock *hb, IROLinear *nd) { + IRO_ASSERT(1247, hb != NULL); + + hb->x0 = nd; +} + +CW_INLINE Boolean PAHeapBlocks_Equal(PAHeapBlock *hb1, PAHeapBlock *hb2) { + IRO_ASSERT(1296, hb1 != NULL); + IRO_ASSERT(1297, hb2 != NULL); + + return (hb1 == hb2) || (hb1->x0 == hb2->x0); +} + +CW_INLINE PALocalVar *PALocalVar_New(void) { + PALocalVar *local = IRO_malloc(sizeof(PALocalVar)); + + IRO_ASSERT(1333, local != NULL); +#ifdef IRO_DEBUG + local->parent = NULL; + local->nextSibling = NULL; +#endif + return local; +} + +CW_INLINE void PALocalVar_InitByObject(PALocalVar *local, Object *obj) { + IRO_ASSERT(1357, local != NULL); + IRO_ASSERT(1358, obj != NULL); + + local->x0 = obj; + if (obj->name && obj->name->name) { + local->x4 = IRO_malloc(strlen(obj->name->name) + 1); + strcpy(local->x4, obj->name->name); + } else { + local->x4 = NULL; + } +} + +CW_INLINE void PALocalVar_InitByName(PALocalVar *local, char *name) { + IRO_ASSERT(1372, local != NULL); + IRO_ASSERT(1373, name != NULL); + + local->x0 = NULL; + local->x4 = IRO_malloc(strlen(name) + 1); + strcpy(local->x4, name); +} + +CW_INLINE Boolean PALocalVars_Equal(PALocalVar *local1, PALocalVar *local2) { + IRO_ASSERT(1419, local1 == NULL || local1 != NULL); + IRO_ASSERT(1420, local2 == NULL || local2 != NULL); + + if (local1 == local2) + return 1; + if (!local1 || !local2) + return 0; + + if (!local1->x0 || !local2->x0) { + if (local1->x4) + return local2->x4 && !strcmp(local1->x4, local2->x4); + } + + return local1->x0 == local2->x0; +} + +CW_INLINE void PALocalVar_SetSth_sub_4847C0(PALocalVar *local, Object *obj) { + IRO_ASSERT(1436, local != NULL); + IRO_ASSERT(1437, obj == NULL || obj != NULL); + + local->x0 = obj; +} + +CW_INLINE Object *PALocalVar_Get0_sub_4847E0(PALocalVar *local) { + IRO_ASSERT(1444, local != NULL); + return local->x0; +} + +CW_INLINE char *PALocalVar_Get4_sub_4847D0(PALocalVar *local) { + IRO_ASSERT(1451, local != NULL); + return local->x4; +} + +CW_INLINE PAMemoryBlock *PAMemoryBlock_New(void) { + PAMemoryBlock *mb = IRO_malloc(sizeof(PAMemoryBlock)); + + IRO_ASSERT(1491, mb != NULL); +#ifdef IRO_DEBUG + mb->kind = PAMEMORYBLOCKKIND_INVALID; +#endif + return mb; +} + +CW_INLINE void PAMemoryBlock_Delete(PAMemoryBlock *mb) { + IRO_ASSERT(1502, mb != NULL); + IRO_ASSERT(1503, mb->kind == PAMEMORYBLOCKKIND_INVALID); + IRO_free(mb); +} + +CW_INLINE void PAMemoryBlock_Init(PAMemoryBlock *mb, PAMemoryBlockKind kind, void *thing) { + IRO_ASSERT(1513, mb != NULL); + IRO_ASSERT(1514, thing == NULL || thing != NULL); + + mb->kind = kind; + switch (mb->kind) { + case PAMEMORYBLOCKKIND_EXTENDEDPARAM: + mb->u.ep = (ExtendedParam *) thing; + break; + case PAMEMORYBLOCKKIND_LOCALVAR: + mb->u.localvar = (PALocalVar *) thing; + break; + case PAMEMORYBLOCKKIND_HEAPBLOCK: + mb->u.heapblock = (PAHeapBlock *) thing; + break; + case PAMEMORYBLOCKKIND_INT: + mb->u.intval = *((CInt64 *) thing); + break; + case PAMEMORYBLOCKKIND_6: + mb->u.x6 = (void *) thing; + break; + default: + CError_FATAL(1535); + } +} + +CW_INLINE void PAMemoryBlock_Term(PAMemoryBlock *mb) { + IRO_ASSERT(1552, mb != NULL); + +#ifdef IRO_DEBUG + mb->kind = PAMEMORYBLOCKKIND_INVALID; +#endif +} + +CW_INLINE Boolean MemoryBlocks_Equal(PAMemoryBlock *mb1, PAMemoryBlock *mb2) { + IRO_ASSERT(1657, mb1 == NULL || mb1 != NULL); + IRO_ASSERT(1658, mb2 == NULL || mb2 != NULL); + + if (mb1 == mb2) + return 1; + + if (!mb1 || !mb2 || mb1->kind != mb2->kind) + return 0; + + switch (mb1->kind) { + case PAMEMORYBLOCKKIND_EXTENDEDPARAM: + return ExtendedParams_Equal(mb1->u.ep, mb2->u.ep); + case PAMEMORYBLOCKKIND_LOCALVAR: + return PALocalVars_Equal(mb1->u.localvar, mb2->u.localvar); + case PAMEMORYBLOCKKIND_HEAPBLOCK: + return PAHeapBlocks_Equal(mb1->u.heapblock, mb2->u.heapblock); + case PAMEMORYBLOCKKIND_INT: + return CInt64_Equal(mb1->u.intval, mb2->u.intval); + case PAMEMORYBLOCKKIND_6: + return mb1->u.x6 == mb2->u.x6; + default: + CError_FATAL(1684); + return 0; + } +} + +CW_INLINE PAMemoryBlockKind PAMemoryBlock_kind(PAMemoryBlock *mb) { + IRO_ASSERT(1692, mb != NULL); + + return mb->kind; +} + +CW_INLINE void *PAMemoryBlock_thing(PAMemoryBlock *mb) { + IRO_ASSERT(1699, mb != NULL); + + switch (mb->kind) { + case PAMEMORYBLOCKKIND_EXTENDEDPARAM: + return mb->u.ep; + case PAMEMORYBLOCKKIND_LOCALVAR: + return mb->u.localvar; + case PAMEMORYBLOCKKIND_HEAPBLOCK: + return mb->u.heapblock; + case PAMEMORYBLOCKKIND_INT: + return &mb->u.intval; + case PAMEMORYBLOCKKIND_6: + return mb->u.x6; + default: + CError_FATAL(1719); + return NULL; + } +} + +CW_INLINE LocationSet *LocationSet_New(void) { + LocationSet *ls = IRO_malloc(sizeof(LocationSet)); + + IRO_ASSERT(1767, ls != NULL); +#ifdef IRO_DEBUG + ls->block = NULL; + ls->rtype = NULL; + ls->u.known.field = cint64_zero; + ls->u.known.stride = 0; +#endif + return ls; +} + +CW_INLINE void LocationSet_Delete(LocationSet *ls) { + IRO_ASSERT(1781, ls != NULL); + IRO_ASSERT(1782, ls != stUnknownLs); + IRO_ASSERT(1783, ls->block == NULL); + IRO_ASSERT(1784, CInt64_IsZero(&ls->u.known.field)); + IRO_ASSERT(1785, ls->u.known.stride == 0); + IRO_ASSERT(1786, ls->rtype == NULL); + IRO_DEBUG_CLEAR(ls, sizeof(LocationSet)); + IRO_free(ls); +} + +CW_INLINE void LocationSet_InitKnown(LocationSet *ls, PAMemoryBlock *block, CInt64 field, UInt32 stride, Type *rtype) { + IRO_ASSERT(1796, ls != NULL); + IRO_ASSERT(1797, ls != stUnknownLs); + IRO_ASSERT(1798, block != NULL); + IRO_ASSERT(1799, rtype == NULL || rtype != NULL); + ls->block = block; + ls->rtype = rtype; + ls->u.known.field = field; + ls->u.known.stride = stride; +} + +CW_INLINE void LocationSet_InitUnknown(LocationSet *ls, Type *rtype, PAMemoryBlock *restriction, LocationSet *bitfieldOf) { + IRO_ASSERT(1809, ls != NULL); + IRO_ASSERT(1810, ls != stUnknownLs); + IRO_ASSERT(1811, rtype == NULL || rtype != NULL); + IRO_ASSERT(1812, restriction == NULL || restriction != NULL); + IRO_ASSERT(1813, bitfieldOf == NULL || bitfieldOf != NULL); + + LocationSet_Copy(ls, stUnknownLs); + ls->rtype = rtype; + ls->u.unknown.restriction = restriction; + if (bitfieldOf) { + ls->u.unknown.bitfieldOf = LocationSet_New(); + LocationSet_Copy(ls->u.unknown.bitfieldOf, bitfieldOf); + } else { + ls->u.unknown.bitfieldOf = NULL; + } +} + +CW_INLINE void LocationSet_Copy(LocationSet *dest, LocationSet *src) { + IRO_ASSERT(1829, src != NULL); + IRO_ASSERT(1830, dest != NULL); + + dest->block = src->block; + dest->rtype = src->rtype; + + if (!LocationSet_IsUnknown(src)) { + dest->u.known.field = src->u.known.field; + dest->u.known.stride = src->u.known.stride; + } else { + dest->u.unknown.restriction = src->u.unknown.restriction; + if (src->u.unknown.bitfieldOf != NULL) { + dest->u.unknown.bitfieldOf = LocationSet_New(); + LocationSet_Copy(dest->u.unknown.bitfieldOf, src->u.unknown.bitfieldOf); + } else { + dest->u.unknown.bitfieldOf = NULL; + } + } +} + +CW_INLINE void LocationSet_Term(LocationSet *ls) { + IRO_ASSERT(1857, ls != NULL); + IRO_ASSERT(1858, ls != stUnknownLs); + +#ifdef IRO_DEBUG + if (LocationSet_IsUnknown(ls) && ls->u.unknown.bitfieldOf) { + LocationSet_Term(ls->u.unknown.bitfieldOf); + LocationSet_Delete(ls->u.unknown.bitfieldOf); + } + ls->block = NULL; + ls->rtype = NULL; + ls->u.known.field = cint64_zero; + ls->u.known.stride = 0; +#endif +} + +CW_INLINE Boolean LocationSets_Overlap(LocationSet *ls1, Type *rtype1, LocationSet *ls2, Type *rtype2) { + Boolean isUnknown1, isUnknown2; + PAMemoryBlock *restriction1, *restriction2; + + IRO_ASSERT(1974, ls1 != NULL); + IRO_ASSERT(1975, rtype1 == NULL || rtype1 != NULL); + IRO_ASSERT(1976, ls2 != NULL); + IRO_ASSERT(1977, rtype2 == NULL || rtype2 != NULL); + + if (ls1 == ls2) + return 1; + + isUnknown1 = LocationSet_IsUnknown(ls1); + if (isUnknown1) + restriction1 = ls1->u.unknown.restriction; + else + restriction1 = NULL; + + isUnknown2 = LocationSet_IsUnknown(ls2); + if (isUnknown2) + restriction2 = ls2->u.unknown.restriction; + else + restriction2 = NULL; + + if ( + (isUnknown1 && !restriction1) || + (isUnknown2 && !restriction2) || + (isUnknown1 && isUnknown2 && MemoryBlocks_Equal(restriction1, restriction2)) + ) + return 1; + + if (isUnknown1 || isUnknown2) + return 0; + + if (MemoryBlocks_Equal(ls1->block, ls2->block)) { + UInt32 size1; + UInt32 size2; + UInt32 i; + CInt64 work; + CInt64 longgcd; + + if (rtype1) + size1 = rtype1->size; + else + size1 = -1; + + if (rtype2) + size2 = rtype2->size; + else + size2 = -1; + + if (ls1->u.known.stride == ls2->u.known.stride) { + CInt64 longsize1; + CInt64 longsize2; + CInt64_SetULong(&longsize1, size1); + CInt64_SetULong(&longsize2, size2); + + return CInt64_Equal(ls1->u.known.field, ls2->u.known.field) || + (CInt64_Less(ls1->u.known.field, ls2->u.known.field) && CInt64_Greater(CInt64_Add(ls1->u.known.field, longsize1), ls2->u.known.field)) || + (CInt64_Less(ls2->u.known.field, ls1->u.known.field) && CInt64_Greater(CInt64_Add(ls2->u.known.field, longsize2), ls1->u.known.field)); + } else { + work = CInt64_Sub(ls1->u.known.field, ls2->u.known.field); + if (CInt64_IsNegative(&work)) + work = CInt64_Neg(work); + + CInt64_SetULong(&longgcd, gcd(ls1->u.known.stride, ls2->u.known.stride)); + if (CInt64_Equal(CInt64_ModU(work, longgcd), cint64_zero)) + return 1; + + if (size1 == -1) + return 1; + + for (i = 1; i < size1; i++) { + CInt64_SetLong(&work, i); + work = CInt64_Add(work, ls1->u.known.field); + work = CInt64_Sub(work, ls2->u.known.field); + if (CInt64_IsNegative(&work)) + work = CInt64_Neg(work); + if (CInt64_Equal(CInt64_ModU(work, longgcd), cint64_zero)) + return 1; + } + + if (size2 == -1) + return 1; + + for (i = 1; i < size2; i++) { + CInt64_SetLong(&work, i); + work = CInt64_Add(work, ls2->u.known.field); + work = CInt64_Sub(work, ls1->u.known.field); + if (CInt64_IsNegative(&work)) + work = CInt64_Neg(work); + if (CInt64_Equal(CInt64_ModU(work, longgcd), cint64_zero)) + return 1; + } + + return 0; + } + } + + return 0; +} + +CW_INLINE Boolean LocationSets_Equal(LocationSet *ls1, LocationSet *ls2) { + IRO_ASSERT(2080, ls1 != NULL); + IRO_ASSERT(2081, ls2 != NULL); + + return + (ls1 == ls2) || + ( + (LocationSet_IsUnknown(ls1) && LocationSet_IsUnknown(ls2)) && + (MemoryBlocks_Equal(ls1->u.unknown.restriction, ls2->u.unknown.restriction)) && + ((ls1->u.unknown.bitfieldOf == ls2->u.unknown.bitfieldOf) || + (ls1->u.unknown.bitfieldOf && ls2->u.unknown.bitfieldOf && LocationSets_Equal(ls1->u.unknown.bitfieldOf, ls2->u.unknown.bitfieldOf))) && + ((ls1->rtype == ls2->rtype) || (ls1->rtype && ls2->rtype && ls1->rtype->size == ls2->rtype->size)) + ) || + ( + (!LocationSet_IsUnknown(ls1) && !LocationSet_IsUnknown(ls2)) && + (ls1->u.known.stride == ls2->u.known.stride) && + ((ls1->rtype == ls2->rtype) || (ls1->rtype && ls2->rtype && ls1->rtype->size == ls2->rtype->size)) && + CInt64_Equal(ls1->u.known.field, ls2->u.known.field) && + MemoryBlocks_Equal(ls1->block, ls2->block) + ); +} + +CW_INLINE Boolean LocationSets_LookupCompatible(LocationSet *ls1, LocationSet *ls2) { + IRO_ASSERT(2119, ls1 != NULL); + IRO_ASSERT(2120, ls2 != NULL); + + if ( + (ls1 == ls2) || + ( + LocationSet_IsUnknown(ls1) && + LocationSet_IsUnknown(ls2) && + MemoryBlocks_Equal(ls1->u.unknown.restriction, ls2->u.unknown.restriction) && + (ls1->rtype == ls2->rtype || (ls1->rtype && ls2->rtype && ls1->rtype->size == ls2->rtype->size)) + )) + return 1; + + if ( + (!LocationSet_IsUnknown(ls1) && !LocationSet_IsUnknown(ls2)) && + (ls1->rtype == ls2->rtype || (ls1->rtype && ls2->rtype && ls1->rtype->size == ls2->rtype->size)) && + MemoryBlocks_Equal(ls1->block, ls2->block) + ) { + CInt64 work; + CInt64 longgcd; + + if (ls1->u.known.stride == ls2->u.known.stride) + return CInt64_Equal(ls1->u.known.field, ls2->u.known.field); + + work = CInt64_Sub(ls1->u.known.field, ls2->u.known.field); + if (CInt64_IsNegative(&work)) + work = CInt64_Neg(work); + + CInt64_SetULong(&longgcd, gcd(ls1->u.known.stride, ls2->u.known.stride)); + return CInt64_Equal(CInt64_ModU(work, longgcd), cint64_zero); + } + + return 0; +} + +CW_INLINE Boolean LocationSet_Contains(LocationSet *ls1, Type *rtype1, LocationSet *ls2, Type *rtype2) { + Boolean unknown1; + Boolean unknown2; + PAMemoryBlock *restriction2; + PAMemoryBlock *restriction1; + CInt64 longsize1; + CInt64 longsize2; + + IRO_ASSERT(2168, ls1 != NULL); + IRO_ASSERT(2169, ls2 != NULL); + IRO_ASSERT(2170, rtype1 != NULL); + IRO_ASSERT(2171, rtype2 != NULL); + + if (ls1 == ls2) + return 1; + + unknown1 = LocationSet_IsUnknown(ls1); + if (unknown1) + restriction1 = ls1->u.unknown.restriction; + else + restriction1 = NULL; + + unknown2 = LocationSet_IsUnknown(ls2); + if (unknown2) + restriction2 = ls2->u.unknown.restriction; + else + restriction2 = NULL; + + if (unknown1) + return !restriction1 || (unknown2 && MemoryBlocks_Equal(restriction2, restriction1)); + + CInt64_SetULong(&longsize1, rtype1->size); + CInt64_SetULong(&longsize2, rtype2->size); + + return + !LocationSet_IsUnknown(ls2) && + (ls1->u.known.stride == 0) && + (ls2->u.known.stride == 0) && + rtype1->size >= rtype2->size && + CInt64_LessEqual(ls1->u.known.field, ls2->u.known.field) && + CInt64_GreaterEqual(CInt64_Add(ls1->u.known.field, longsize1), CInt64_Add(ls2->u.known.field, longsize2)) && + MemoryBlocks_Equal(ls1->block, ls2->block); +} + +CW_INLINE Boolean LocationSet_IsUnknown(LocationSet *ls) { + IRO_ASSERT(2233, ls != NULL); + + return (ls == stUnknownLs) || (ls->block == stUnknownMb); +} + +CW_INLINE Boolean LocationSet_sub_48AF30(LocationSet *ls) { + return + !LocationSet_IsUnknown(ls) && + (ls->u.known.stride == 0) && + CInt64_IsZero(&ls->u.known.field) && + PAMemoryBlock_kind(ls->block) == PAMEMORYBLOCKKIND_LOCALVAR && + !PAMemoryBlock_thing(ls->block); +} + +CW_INLINE void LocationSet_SetRtype(LocationSet *ls, Type *rtype) { + IRO_ASSERT(2263, ls != NULL); + IRO_ASSERT(2264, ls != stUnknownLs); + IRO_ASSERT(2265, rtype != NULL); + + ls->rtype = rtype; +} + +CW_INLINE void SetsLocationSetField_sub_4851B0(LocationSet *ls, CInt64 field) { + IRO_ASSERT(2272, ls != NULL); + IRO_ASSERT(2273, !LocationSet_IsUnknown(ls)); + + ls->u.known.field = field; +} + +CW_INLINE void SetsLocationSetStride_sub_4852D0(LocationSet *ls, SInt32 stride) { + IRO_ASSERT(2280, ls != NULL); + IRO_ASSERT(2281, !LocationSet_IsUnknown(ls)); + + ls->u.known.stride = stride; +} + +CW_INLINE PAMemoryBlock *LocationSet_block(LocationSet *ls) { + IRO_ASSERT(2298, ls != NULL); + + return ls->block; +} + +CW_INLINE Type *LocationSet_rtype(LocationSet *ls) { + IRO_ASSERT(2306, ls != NULL); + IRO_ASSERT(2307, ls != stUnknownLs); + + return ls->rtype; +} + +CW_INLINE CInt64 LocationSet_field(LocationSet *ls) { + IRO_ASSERT(2314, ls != NULL); + IRO_ASSERT(2315, !LocationSet_IsUnknown(ls)); + + return ls->u.known.field; +} + +CW_INLINE UInt32 LocationSet_stride(LocationSet *ls) { + IRO_ASSERT(2322, ls != NULL); + IRO_ASSERT(2323, !LocationSet_IsUnknown(ls)); + + return ls->u.known.stride; +} + +CW_INLINE PAMemoryBlock *LocationSet_restriction(LocationSet *ls) { + IRO_ASSERT(2330, ls != NULL); + IRO_ASSERT(2331, LocationSet_IsUnknown(ls)); + + return ls->u.unknown.restriction; +} + +CW_INLINE LocationSet *LocationSet_bitfieldOf(LocationSet *ls) { + IRO_ASSERT(2338, ls != NULL); + IRO_ASSERT(2339, LocationSet_IsUnknown(ls)); + + return ls->u.unknown.bitfieldOf; +} + +CW_INLINE LocationSetSet *LocationSetSet_New(void) { + LocationSetSet *lss = IRO_malloc(sizeof(LocationSetSet)); + + IRO_ASSERT(2356, lss != NULL); +#ifdef IRO_DEBUG + lss->loc = NULL; + lss->otherLocs = NULL; + lss->count = 0; +#endif + return lss; +} + +CW_INLINE void LocationSetSet_Delete(LocationSetSet *lss) { + IRO_ASSERT(2369, lss != NULL); + IRO_ASSERT(2370, lss->loc == NULL); + IRO_ASSERT(2371, lss->otherLocs == NULL); + IRO_ASSERT(2372, lss->count == 0); + IRO_DEBUG_CLEAR(lss, sizeof(LocationSetSet)); + IRO_free(lss); +} + +CW_INLINE void LocationSetSet_Init(LocationSetSet *lss) { + IRO_ASSERT(2382, lss != NULL); + + lss->loc = NULL; + lss->otherLocs = NULL; + lss->count = 0; +} + +CW_INLINE void LocationSetSet_Copy(LocationSetSet *dest, LocationSetSet *src) { + IRO_ASSERT(2391, dest != NULL); + IRO_ASSERT(2392, src != NULL); + + dest->loc = NULL; + dest->otherLocs = NULL; + dest->count = 0; + LocationSetSet_AddSet(dest, src); +} + +CW_INLINE void LocationSetSet_Term(LocationSetSet *lss) { + IRO_ASSERT(2402, lss != NULL); + + LocationSetSet_RemoveAll(lss); + +#ifdef IRO_DEBUG + lss->loc = NULL; + lss->otherLocs = NULL; + lss->count = 0; +#endif +} + +CW_INLINE void LocationSetSet_ForEach(LocationSetSet *lss, void (*action)(LocationSet *, void *), void *refcon) { + IRO_ASSERT(2446, lss != NULL); + IRO_ASSERT(2447, action != NULL); + IRO_ASSERT(2448, refcon == NULL || refcon != NULL); + + while (lss && lss->loc) { + action(lss->loc, refcon); + lss = lss->otherLocs; + } +} + +CW_INLINE LocationSet *LocationSetSet_Find(LocationSetSet *lss, LocationSet *ls) { + IRO_ASSERT(2458, lss != NULL); + IRO_ASSERT(2459, ls != NULL); + + while (lss && lss->loc) { + if (LocationSets_Equal(lss->loc, ls)) + return lss->loc; + lss = lss->otherLocs; + } + + return NULL; +} + +CW_INLINE LocationSet *LocationSetSet_FindUnknown(LocationSetSet *lss) { + IRO_ASSERT(2470, lss != NULL); + + if (!lss->loc) + return stUnknownLs; + + while (lss && lss->loc) { + if (LocationSet_IsUnknown(lss->loc)) + return lss->loc; + lss = lss->otherLocs; + } + + return NULL; +} + +CW_INLINE LocationSet *LocationSetSet_FindFirst(LocationSetSet *lss) { + IRO_ASSERT(2498, lss != NULL); + + return lss->loc; +} + +CW_INLINE int LocationSetSet_Count(LocationSetSet *lss) { + IRO_ASSERT(2505, lss != NULL); + + return lss->count; +} + +CW_INLINE void LocationSetSet_RemoveAllWithMemoryBlock(LocationSetSet *lss, PAMemoryBlock *block) { + LocationSetSet *first; + LocationSetSet *prev; + LocationSetSet *next; + LocationSetSet *tmp; + + IRO_ASSERT(2514, lss != NULL); + IRO_ASSERT(2515, block != NULL); + + first = lss; + prev = NULL; + while (lss && lss->loc) { + next = lss->otherLocs; + if (MemoryBlocks_Equal(block, lss->loc->block)) { + if (lss->loc != stUnknownLs) { + LocationSet_Term(lss->loc); + LocationSet_Delete(lss->loc); + } + if (!prev) { + if (lss->otherLocs == NULL) { + lss->loc = NULL; + prev = lss; + } else { + tmp = lss->otherLocs; + lss->loc = lss->otherLocs->loc; + lss->otherLocs = lss->otherLocs->otherLocs; + tmp->loc = NULL; + tmp->otherLocs = NULL; + LocationSetSet_Term(tmp); + LocationSetSet_Delete(tmp); + prev = NULL; + next = lss; + } + } else { + prev->otherLocs = lss->otherLocs; + lss->loc = NULL; + lss->otherLocs = NULL; + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + prev = lss; + } + first->count--; + } + lss = next; + } +} + +CW_INLINE void LocationSetSet_SimpleAdd(LocationSetSet *lss, LocationSet *ls) { + IRO_ASSERT(2572, lss != NULL); + IRO_ASSERT(2573, ls != NULL); + + if (!LocationSet_IsUnknown(ls) && lss->count < 4) { + LocationSet *ls2; + + if (ls == stUnknownLs) { + ls2 = stUnknownLs; + } else { + ls2 = LocationSet_New(); + LocationSet_Copy(ls2, ls); + } + + if (lss->loc) { + LocationSetSet *lss2 = LocationSetSet_New(); + LocationSetSet_Init(lss2); + lss2->loc = lss->loc; + lss2->otherLocs = lss->otherLocs; + lss->otherLocs = lss2; + } + + lss->loc = ls2; + lss->count++; + } else { + LocationSet *ls2; + + LocationSetSet_RemoveAll(lss); + ls2 = LocationSet_New(); + if (LocationSet_IsUnknown(ls)) { + LocationSet_Copy(ls2, ls); + } else { + LocationSet_Copy(ls2, stUnknownLs); + if (ls->rtype) + LocationSet_SetRtype(ls2, ls->rtype); + } + + lss->loc = ls2; + lss->count = 1; + } +} + +CW_INLINE void LocationSetSet_Add(LocationSetSet *lss, LocationSet *ls) { + IRO_ASSERT(2622, lss != NULL); + IRO_ASSERT(2623, ls != NULL); + + if (!lss->loc || (!LocationSet_IsUnknown(lss->loc) && !LocationSetSet_Find(lss, ls))) { + if (!LocationSet_IsUnknown(ls) && ls->u.known.stride) + LocationSetSet_RemoveAllWithMemoryBlock(lss, ls->block); + LocationSetSet_SimpleAdd(lss, ls); + } +} + +CW_INLINE void LocationSetSet_AddUnknown(LocationSetSet *lss, Type *rtype, PAMemoryBlock *restriction, LocationSet *bitfieldOf) { + LocationSet *ls; + + IRO_ASSERT(2643, lss != NULL); + IRO_ASSERT(2644, rtype == NULL || rtype != NULL); + IRO_ASSERT(2645, restriction == NULL || restriction != NULL); + IRO_ASSERT(2646, bitfieldOf == NULL || bitfieldOf != NULL); + + ls = LocationSet_New(); + LocationSet_InitUnknown(ls, rtype, restriction, bitfieldOf); + LocationSetSet_Add(lss, ls); + LocationSet_Term(ls); + LocationSet_Delete(ls); +} + +CW_INLINE void LocationSetSet_Remove(LocationSetSet *lss, LocationSet *ls) { + LocationSetSet *prev; + LocationSetSet *first; + LocationSetSet *tmp; + + IRO_ASSERT(2659, lss != NULL); + IRO_ASSERT(2660, ls != NULL); + + first = lss; + prev = NULL; + while (lss && lss->loc) { + if (LocationSets_Equal(lss->loc, ls)) { + if (lss->loc != stUnknownLs) { + LocationSet_Term(lss->loc); + LocationSet_Delete(lss->loc); + } + if (!prev) { + if (lss->otherLocs == NULL) { + lss->loc = NULL; + } else { + tmp = lss->otherLocs; + lss->loc = lss->otherLocs->loc; + lss->otherLocs = lss->otherLocs->otherLocs; + tmp->loc = NULL; + tmp->otherLocs = NULL; + LocationSetSet_Term(tmp); + LocationSetSet_Delete(tmp); + } + } else { + prev->otherLocs = lss->otherLocs; + lss->loc = NULL; + lss->otherLocs = NULL; + LocationSetSet_Term(lss); + LocationSetSet_Delete(lss); + } + first->count--; + return; + } + + prev = lss; + lss = lss->otherLocs; + } +} + +CW_INLINE void LocationSetSet_RemoveAll(LocationSetSet *lss) { + IRO_ASSERT(2707, lss != NULL); + + while (lss && lss->loc) + LocationSetSet_Remove(lss, lss->loc); +} + +CW_INLINE void LocationSetSet_AddSetAction(LocationSet *ls, void *refcon) { + IRO_ASSERT(2717, ls != NULL); + IRO_ASSERT(2718, refcon != NULL); + + LocationSetSet_Add((LocationSetSet *) refcon, ls); +} + +CW_INLINE void LocationSetSet_SimpleAddSetAction(LocationSet *ls, void *refcon) { + IRO_ASSERT(2725, ls != NULL); + IRO_ASSERT(2726, refcon != NULL); + + LocationSetSet_SimpleAdd((LocationSetSet *) refcon, ls); +} + +CW_INLINE void LocationSetSet_AddSet(LocationSetSet *dest, LocationSetSet *src) { + IRO_ASSERT(2733, dest != NULL); + IRO_ASSERT(2734, src != NULL); + + if (dest->count) + LocationSetSet_ForEach(src, LocationSetSet_AddSetAction, dest); + else + LocationSetSet_ForEach(src, LocationSetSet_SimpleAddSetAction, dest); +} + +CW_INLINE void LocationSetSet_RemoveSetAction(LocationSet *ls, void *refcon) { + IRO_ASSERT(2744, ls != NULL); + IRO_ASSERT(2745, refcon != NULL); + + LocationSetSet_Remove((LocationSetSet *) refcon, ls); +} + +CW_INLINE void LocationSetSet_sub_488700(LocationSetSet *dest, LocationSetSet *src) { + IRO_ASSERT(2752, dest != NULL); + IRO_ASSERT(2753, src != NULL); + + LocationSetSet_ForEach(src, LocationSetSet_RemoveSetAction, dest); +} + +CW_INLINE Boolean LocationSetSets_Equal(LocationSetSet *lss1, LocationSetSet *lss2) { + IRO_ASSERT(2826, lss1 != NULL); + IRO_ASSERT(2827, lss2 != NULL); + + if (lss1 == lss2) + return 1; + if (LocationSetSet_Count(lss1) != LocationSetSet_Count(lss2)) + return 0; + + while (lss1 && lss1->loc) { + if (!LocationSetSet_Find(lss2, lss1->loc)) + return 0; + lss1 = lss1->otherLocs; + } + + return 1; +} + +CW_INLINE ParamMapping *ParamMapping_New(void) { + ParamMapping *pm = IRO_malloc(sizeof(ParamMapping)); + + IRO_ASSERT(2885, pm != NULL); +#ifdef IRO_DEBUG + pm->actual = NULL; + pm->formal = NULL; + pm->extended = NULL; +#endif + return pm; +} + +CW_INLINE void ParamMapping_Delete(ParamMapping *pm) { + IRO_ASSERT(2898, pm != NULL); + IRO_ASSERT(2899, pm->actual == NULL); + IRO_ASSERT(2900, pm->formal == NULL); + IRO_ASSERT(2901, pm->extended == NULL); + IRO_DEBUG_CLEAR(pm, sizeof(ParamMapping)); + IRO_free(pm); +} + +CW_INLINE void ParamMapping_Init_PROBABLY(ParamMapping *pm, IROLinear *actual, Object *formal, ExtendedParam *extended) { + IRO_ASSERT(2911, pm != NULL); + + pm->actual = actual; + pm->formal = formal; + pm->extended = extended; +} + +CW_INLINE void ParamMapping_Copy(ParamMapping *dest, ParamMapping *src) { + IRO_ASSERT(2920, src != NULL); + IRO_ASSERT(2921, dest != NULL); + + dest->actual = src->actual; + dest->formal = src->formal; + dest->extended = src->extended; +} + +CW_INLINE void ParamMapping_Term(ParamMapping *pm) { + IRO_ASSERT(2933, pm != NULL); + +#ifdef IRO_DEBUG + pm->actual = NULL; + pm->formal = NULL; + pm->extended = NULL; +#endif +} + +CW_INLINE void ParamMapping_SetExtended(ParamMapping *pm, ExtendedParam *ep) { + IRO_ASSERT(2992, pm != NULL); + + pm->extended = ep; +} + +CW_INLINE IROLinear *ParamMapping_actual(ParamMapping *pm) { + IRO_ASSERT(2999, pm != NULL); + + return pm->actual; +} + +CW_INLINE ExtendedParam *ParamMapping_extended(ParamMapping *pm) { + IRO_ASSERT(3011, pm != NULL); + + return pm->extended; +} + +CW_INLINE ParamMappingFunction *ParamMappingFunction_New(void) { + ParamMappingFunction *pmf = IRO_malloc(sizeof(ParamMappingFunction)); + + IRO_ASSERT(3026, pmf != NULL); +#ifdef IRO_DEBUG + pmf->mapping = NULL; + pmf->otherMappings = NULL; +#endif + return pmf; +} + +CW_INLINE void ParamMappingFunction_Delete(ParamMappingFunction *pmf) { + IRO_ASSERT(3039, pmf != NULL); + IRO_ASSERT(3040, pmf->mapping == NULL); + IRO_ASSERT(3041, pmf->otherMappings == NULL); + IRO_DEBUG_CLEAR(pmf, sizeof(ParamMappingFunction)); + IRO_free(pmf); +} + +CW_INLINE void ParamMappingFunction_Init(ParamMappingFunction *pmf) { + IRO_ASSERT(3050, pmf != NULL); + + pmf->mapping = NULL; + pmf->otherMappings = NULL; +} + +CW_INLINE void ParamMappingFunction_Copy(ParamMappingFunction *dest, ParamMappingFunction *src) { + IRO_ASSERT(3058, src != NULL); + IRO_ASSERT(3059, dest != NULL); + + dest->mapping = NULL; + dest->otherMappings = NULL; + ParamMappingFunction_AddAllMaybe_sub_487C50(dest, src); +} + +CW_INLINE void ParamMappingFunction_Term(ParamMappingFunction *pmf) { + IRO_ASSERT(3068, pmf != NULL); + + ParamMappingFunction_RemoveAll(pmf); + +#ifdef IRO_DEBUG + pmf->mapping = NULL; + pmf->otherMappings = NULL; +#endif +} + +CW_INLINE void pmf_sub_487C70(ParamMappingFunction *pmf, void (*action)(ParamMapping *, void *), void *refcon) { + IRO_ASSERT(3111, pmf != NULL); + IRO_ASSERT(3112, action != NULL); + IRO_ASSERT(3113, refcon == NULL || refcon != NULL); + + while (pmf && pmf->mapping) { + action(pmf->mapping, refcon); + pmf = pmf->otherMappings; + } +} + +CW_INLINE ParamMapping *ParamMappingFunction_FindMappingByFormal(ParamMappingFunction *pmf, Object *formal) { + IRO_ASSERT(3123, pmf != NULL); + IRO_ASSERT(3124, formal != NULL); + + while (pmf && pmf->mapping) { + if (pmf->mapping->formal == formal) + return pmf->mapping; + pmf = pmf->otherMappings; + } + + return NULL; +} + +CW_INLINE void Pmf_Add_sub_486610(ParamMappingFunction *pmf, ParamMapping *mapping) { + ParamMapping *existing; + + IRO_ASSERT(3138, pmf != NULL); + IRO_ASSERT(3139, mapping != NULL); + + existing = ParamMappingFunction_FindMappingByFormal(pmf, mapping->formal); + if (!existing) { + existing = ParamMapping_New(); + ParamMapping_Copy(existing, mapping); + if (pmf->mapping) { + ParamMappingFunction *newPMF = ParamMappingFunction_New(); + ParamMappingFunction_Init(newPMF); + newPMF->mapping = pmf->mapping; + newPMF->otherMappings = pmf->otherMappings; + pmf->otherMappings = newPMF; + } + pmf->mapping = existing; + } else { + existing->actual = mapping->actual; + existing->extended = mapping->extended; + } +} + +CW_INLINE void ParamMappingFunction_Remove(ParamMappingFunction *pmf, ParamMapping *mapping) { + ParamMappingFunction *prev; + ParamMappingFunction *tmp; + + IRO_ASSERT(3170, pmf != NULL); + IRO_ASSERT(3171, mapping != NULL); + + prev = NULL; + while (pmf && pmf->mapping) { + if (pmf->mapping->formal == mapping->formal) { + ParamMapping_Term(pmf->mapping); + ParamMapping_Delete(pmf->mapping); + if (!prev) { + if (pmf->otherMappings == NULL) { + pmf->mapping = NULL; + } else { + tmp = pmf->otherMappings; + pmf->mapping = pmf->otherMappings->mapping; + pmf->otherMappings = pmf->otherMappings->otherMappings; + tmp->mapping = NULL; + tmp->otherMappings = NULL; + ParamMappingFunction_Term(tmp); + ParamMappingFunction_Delete(tmp); + } + } else { + prev->otherMappings = pmf->otherMappings; + pmf->mapping = NULL; + pmf->otherMappings = NULL; + ParamMappingFunction_Term(pmf); + ParamMappingFunction_Delete(pmf); + } + return; + } + + prev = pmf; + pmf = pmf->otherMappings; + } +} + +CW_INLINE void ParamMappingFunction_RemoveAll(ParamMappingFunction *pmf) { + IRO_ASSERT(3213, pmf != NULL); + + while (pmf && pmf->mapping) + ParamMappingFunction_Remove(pmf, pmf->mapping); +} + +CW_INLINE void ParamMappingFunction_AddFunctionAction(ParamMapping *mapping, void *refcon) { + IRO_ASSERT(3223, mapping != NULL); + IRO_ASSERT(3224, refcon != NULL); + + Pmf_Add_sub_486610((ParamMappingFunction *) refcon, mapping); +} + +CW_INLINE void ParamMappingFunction_AddAllMaybe_sub_487C50(ParamMappingFunction *dest, ParamMappingFunction *src) { + IRO_ASSERT(3231, dest != NULL); + IRO_ASSERT(3232, src != NULL); + + pmf_sub_487C70(src, ParamMappingFunction_AddFunctionAction, dest); +} + +CW_INLINE PointsToEntry *PointsToEntry_New(void) { + PointsToEntry *pte = IRO_malloc(sizeof(PointsToEntry)); + + IRO_ASSERT(3288, pte != NULL); +#ifdef IRO_DEBUG + pte->loc = NULL; + pte->locs = NULL; +#endif + return pte; +} + +CW_INLINE void PointsToEntry_Delete(PointsToEntry *pte) { + IRO_ASSERT(3300, pte != NULL); + IRO_ASSERT(3301, pte->loc == NULL); + IRO_ASSERT(3302, pte->locs == NULL); + IRO_DEBUG_CLEAR(pte, sizeof(PointsToEntry)); + IRO_free(pte); +} + +CW_INLINE void PointsToEntry_Init(PointsToEntry *pte, LocationSet *loc, LocationSetSet *locs) { + IRO_ASSERT(3312, pte != NULL); + IRO_ASSERT(3313, loc != NULL); + IRO_ASSERT(3314, !LocationSet_IsUnknown(loc)); + IRO_ASSERT(3315, locs != NULL); + + pte->loc = LocationSet_New(); + LocationSet_Copy(pte->loc, loc); + + pte->locs = LocationSetSet_New(); + LocationSetSet_Copy(pte->locs, locs); +} + +CW_INLINE void PointsToEntry_Copy(PointsToEntry *dest, PointsToEntry *src) { + IRO_ASSERT(3325, src != NULL); + IRO_ASSERT(3326, dest != NULL); + + PointsToEntry_Init(dest, src->loc, src->locs); +} + +CW_INLINE void PointsToEntry_Term(PointsToEntry *pte) { + IRO_ASSERT(3333, pte != NULL); + + LocationSet_Term(pte->loc); + LocationSet_Delete(pte->loc); + LocationSetSet_Term(pte->locs); + LocationSetSet_Delete(pte->locs); + +#ifdef IRO_DEBUG + pte->loc = NULL; + pte->locs = NULL; +#endif +} + +CW_INLINE Boolean PointsToEntries_Equal(PointsToEntry *pte1, PointsToEntry *pte2) { + IRO_ASSERT(3381, pte1 != NULL); + IRO_ASSERT(3382, pte2 != NULL); + + if (pte1 == pte2) + return 1; + + return LocationSets_Equal(pte1->loc, pte2->loc) && LocationSetSets_Equal(pte1->locs, pte2->locs); +} + +CW_INLINE LocationSet *PointsToEntry_loc(PointsToEntry *pte) { + IRO_ASSERT(3407, pte != NULL); + + return pte->loc; +} + +CW_INLINE LocationSetSet *PointsToEntry_locs(PointsToEntry *pte) { + IRO_ASSERT(3414, pte != NULL); + + return pte->locs; +} + +CW_INLINE PointsToFunction *PointsToFunction_New(void) { + PointsToFunction *pointsToFunc = IRO_malloc(sizeof(PointsToFunction)); + + IRO_ASSERT(3430, pointsToFunc != NULL); +#ifdef IRO_DEBUG + pointsToFunc->pte = NULL; + pointsToFunc->otherPtes = NULL; +#endif + return pointsToFunc; +} + +CW_INLINE void PointsToFunction_Delete(PointsToFunction *pointsToFunc) { + IRO_ASSERT(3442, pointsToFunc != NULL); + IRO_ASSERT(3443, pointsToFunc->pte == NULL); + IRO_ASSERT(3444, pointsToFunc->otherPtes == NULL); + IRO_DEBUG_CLEAR(pointsToFunc, sizeof(PointsToFunction)); + IRO_free(pointsToFunc); +} + +CW_INLINE void PointsToFunction_Init(PointsToFunction *pointsToFunc) { + IRO_ASSERT(3454, pointsToFunc != NULL); + + pointsToFunc->pte = NULL; + pointsToFunc->otherPtes = NULL; +} + +CW_INLINE void PointsToFunction_Copy(PointsToFunction *dest, PointsToFunction *src) { + IRO_ASSERT(3462, src != NULL); + IRO_ASSERT(3463, dest != NULL); + + dest->pte = NULL; + dest->otherPtes = NULL; + PointsToFunction_AddAllIGuess_sub_487D80(dest, src); +} + +CW_INLINE void PointsToFunction_Term(PointsToFunction *pointsToFunc) { + IRO_ASSERT(3472, pointsToFunc != NULL); + + PointsToFunction_RemoveAll(pointsToFunc); + +#ifdef IRO_DEBUG + pointsToFunc->pte = NULL; + pointsToFunc->otherPtes = NULL; +#endif +} + +CW_INLINE void PointsToFunction_ForEach(PointsToFunction *pointsToFunc, void (*action)(PointsToEntry *, void *), void *refcon) { + IRO_ASSERT(3515, pointsToFunc != NULL); + IRO_ASSERT(3516, action != NULL); + IRO_ASSERT(3517, refcon == NULL || refcon != NULL); + + while (pointsToFunc && pointsToFunc->pte) { + action(pointsToFunc->pte, refcon); + pointsToFunc = pointsToFunc->otherPtes; + } +} + +CW_INLINE PointsToEntry *PointsToFunction_FindByLocationSet(PointsToFunction *pointsToFunc, LocationSet *ls) { + IRO_ASSERT(3527, pointsToFunc != NULL); + IRO_ASSERT(3528, ls != NULL); + + while (pointsToFunc && pointsToFunc->pte) { + if (LocationSets_Equal(pointsToFunc->pte->loc, ls)) + return pointsToFunc->pte; + pointsToFunc = pointsToFunc->otherPtes; + } + + return NULL; +} + +CW_INLINE PointsToEntry *PointsToFunction_FindFirst(PointsToFunction *pointsToFunc) { + IRO_ASSERT(3539, pointsToFunc != NULL); + + return pointsToFunc->pte; +} + +CW_INLINE PointsToEntry *PointsToFunction_FindByLookupCompatibleLocationSet(PointsToFunction *pointsToFunc, LocationSet *ls) { + IRO_ASSERT(3546, pointsToFunc != NULL); + IRO_ASSERT(3547, ls != NULL); + + while (pointsToFunc && pointsToFunc->pte) { + if (ls->u.known.stride) { + if (LocationSets_Equal(pointsToFunc->pte->loc, ls)) + return pointsToFunc->pte; + } else if (LocationSets_LookupCompatible(pointsToFunc->pte->loc, ls)) { + return pointsToFunc->pte; + } + pointsToFunc = pointsToFunc->otherPtes; + } + + return NULL; +} + +CW_INLINE PointsToEntry *PointsToFunction_FindContainingLocationSet(PointsToFunction *pointsToFunc, LocationSet *ls, Type *rtype) { + IRO_ASSERT(3565, pointsToFunc != NULL); + IRO_ASSERT(3566, ls != NULL); + IRO_ASSERT(3567, rtype != NULL); + + while (pointsToFunc && pointsToFunc->pte) { + if (pointsToFunc->pte->locs->loc && !LocationSet_IsUnknown(pointsToFunc->pte->locs->loc)) { + if (!pointsToFunc->pte->locs->otherLocs && LocationSet_Contains(pointsToFunc->pte->loc, pointsToFunc->pte->locs->loc->rtype, ls, rtype)) + return pointsToFunc->pte; + } + pointsToFunc = pointsToFunc->otherPtes; + } + + return NULL; +} + +CW_INLINE void PointsToFunction_RemoveOverlappingLocations(PointsToFunction *pointsToFunc, PointsToEntry *pte) { + Type *rtype1; + Type *rtype2; + LocationSet *ls; + PointsToFunction *prev; + PointsToFunction *next; + PointsToFunction *tmp; + + IRO_ASSERT(3601, pointsToFunc != NULL); + IRO_ASSERT(3602, pte != NULL); + IRO_ASSERT(3603, pte->locs != NULL); + + if (pte->locs->loc && pte->locs->loc != stUnknownLs) + rtype1 = pte->locs->loc->rtype; + else + rtype1 = NULL; + ls = pte->loc; + IRO_ASSERT(3614, ls != NULL); + + prev = NULL; + while (pointsToFunc && pointsToFunc->pte) { + next = pointsToFunc->otherPtes; + if (pointsToFunc->pte->locs->loc && pointsToFunc->pte->locs->loc != stUnknownLs) + rtype2 = pointsToFunc->pte->locs->loc->rtype; + else + rtype2 = NULL; + + if (LocationSets_Overlap(ls, rtype1, pointsToFunc->pte->loc, rtype2)) { + PointsToEntry_Term(pointsToFunc->pte); + PointsToEntry_Delete(pointsToFunc->pte); + if (!prev) { + if (pointsToFunc->otherPtes == NULL) { + pointsToFunc->pte = NULL; + prev = pointsToFunc; + } else { + tmp = pointsToFunc->otherPtes; + pointsToFunc->pte = pointsToFunc->otherPtes->pte; + pointsToFunc->otherPtes = pointsToFunc->otherPtes->otherPtes; + tmp->pte = NULL; + tmp->otherPtes = NULL; + PointsToFunction_Term(tmp); + PointsToFunction_Delete(tmp); + prev = NULL; + next = pointsToFunc; + } + } else { + prev->otherPtes = pointsToFunc->otherPtes; + pointsToFunc->pte = NULL; + pointsToFunc->otherPtes = NULL; + PointsToFunction_Term(pointsToFunc); + PointsToFunction_Delete(pointsToFunc); + prev = pointsToFunc; + } + } + + pointsToFunc = next; + } +} + +CW_INLINE Boolean ShouldAddNewPointsToEntryToFunction(PointsToFunction *pointsToFunc, PointsToEntry *pte) { + Boolean flag; + Boolean isKnown; + SInt32 stride; + PointsToFunction *next; + LocationSet *loc; + LocationSet *loc2; + Type *rtype1; + Type *rtype2; + LocationSetSet *locs2; + LocationSet *tmp; + LocationSet *unknown; + Boolean flag2; + Boolean flag3; + + IRO_ASSERT(3675, pointsToFunc != NULL); + IRO_ASSERT(3676, pte != NULL); + IRO_ASSERT(3677, pte->locs != NULL); + IRO_ASSERT(3678, PointsToFunction_FindByLookupCompatibleLocationSet(pointsToFunc, pte->loc) == NULL); + IRO_ASSERT(3679, (unknown = LocationSetSet_FindFirst(pte->locs)) != NULL); + IRO_ASSERT(3680, LocationSet_IsUnknown(unknown)); + IRO_ASSERT(3681, LocationSet_bitfieldOf(unknown) == NULL); + IRO_ASSERT(3682, LocationSet_restriction(unknown) == NULL); + + if (pte->locs->loc && pte->locs->loc != stUnknownLs) + rtype1 = pte->locs->loc->rtype; + else + rtype1 = NULL; + + loc = pte->loc; + IRO_ASSERT(3693, loc != NULL); + + isKnown = !LocationSet_IsUnknown(loc); + if (isKnown) + stride = LocationSet_stride(loc); + + flag = 0; + while (pointsToFunc && pointsToFunc->pte) { + next = pointsToFunc->otherPtes; + + locs2 = pointsToFunc->pte->locs; + + if (locs2->loc && locs2->loc != stUnknownLs) + rtype2 = locs2->loc->rtype; + else + rtype2 = NULL; + + loc2 = pointsToFunc->pte->loc; + + flag2 = !(tmp = LocationSetSet_FindFirst(locs2)) || + !LocationSet_IsUnknown(tmp) || + LocationSet_bitfieldOf(tmp) || + LocationSet_restriction(tmp); + + flag3 = LocationSets_Overlap(loc, rtype1, loc2, rtype2); + + if (!flag && flag3) + flag = 1; + + if (flag3 && (flag2 || (isKnown && stride && LocationSet_stride(loc2) == 0))) + return 1; + + pointsToFunc = next; + } + + return !flag; +} + +CW_INLINE Boolean PointsToFunction_SimpleAdd(PointsToFunction *pointsToFunc, PointsToEntry *pte) { + PointsToEntry *newPTE; + + IRO_ASSERT(3741, pointsToFunc != NULL); + IRO_ASSERT(3742, pte != NULL); + + newPTE = PointsToEntry_New(); + PointsToEntry_Copy(newPTE, pte); + if (pointsToFunc->pte) { + PointsToFunction *newPointsToFunc = PointsToFunction_New(); + PointsToFunction_Init(newPointsToFunc); + newPointsToFunc->pte = pointsToFunc->pte; + newPointsToFunc->otherPtes = pointsToFunc->otherPtes; + pointsToFunc->otherPtes = newPointsToFunc; + } + pointsToFunc->pte = newPTE; + return 1; +} + +CW_INLINE Boolean PointsToFunction_Add(PointsToFunction *pointsToFunc, PointsToEntry *pte) { + IRO_ASSERT(3766, pointsToFunc != NULL); + IRO_ASSERT(3767, pte != NULL); + + if (!PointsToFunction_FindByLookupCompatibleLocationSet(pointsToFunc, pte->loc)) { + LocationSet *ls; + if (!(ls = LocationSetSet_FindFirst(pte->locs)) || !LocationSet_IsUnknown(ls) || LocationSet_bitfieldOf(ls) || + LocationSet_restriction(ls) || ShouldAddNewPointsToEntryToFunction(pointsToFunc, pte)) { + PointsToFunction_RemoveOverlappingLocations(pointsToFunc, pte); + if (!LocationSet_IsUnknown(pte->loc) || pte->loc->rtype) + PointsToFunction_SimpleAdd(pointsToFunc, pte); + return 1; + } + } + + return 0; +} + +CW_INLINE Boolean PointsToFunction_AddWithoutChecking(PointsToFunction *pointsToFunc, PointsToEntry *pte) { + LocationSet *ls; + + IRO_ASSERT(3793, pointsToFunc != NULL); + IRO_ASSERT(3794, pte != NULL); + + if (!(ls = LocationSetSet_FindFirst(pte->locs)) || !LocationSet_IsUnknown(ls) || LocationSet_bitfieldOf(ls) || + LocationSet_restriction(ls) || ShouldAddNewPointsToEntryToFunction(pointsToFunc, pte)) { + PointsToFunction_RemoveOverlappingLocations(pointsToFunc, pte); + if (!LocationSet_IsUnknown(pte->loc) || pte->loc->rtype) + PointsToFunction_SimpleAdd(pointsToFunc, pte); + return 1; + } + + return 0; +} + +CW_INLINE void PointsToFunction_RemoveByLocationSet(PointsToFunction *pointsToFunc, LocationSet *ls) { + PointsToFunction *prev; + PointsToFunction *tmp; + + IRO_ASSERT(3818, pointsToFunc != NULL); + IRO_ASSERT(3819, ls != NULL); + IRO_ASSERT(3820, !LocationSet_IsUnknown(ls)); + + prev = NULL; + while (pointsToFunc && pointsToFunc->pte) { + if (LocationSets_Equal(pointsToFunc->pte->loc, ls)) { + PointsToEntry_Term(pointsToFunc->pte); + PointsToEntry_Delete(pointsToFunc->pte); + if (!prev) { + if (pointsToFunc->otherPtes == NULL) { + pointsToFunc->pte = NULL; + } else { + tmp = pointsToFunc->otherPtes; + pointsToFunc->pte = pointsToFunc->otherPtes->pte; + pointsToFunc->otherPtes = pointsToFunc->otherPtes->otherPtes; + tmp->pte = NULL; + tmp->otherPtes = NULL; + PointsToFunction_Term(tmp); + PointsToFunction_Delete(tmp); + } + } else { + prev->otherPtes = pointsToFunc->otherPtes; + pointsToFunc->pte = NULL; + pointsToFunc->otherPtes = NULL; + PointsToFunction_Term(pointsToFunc); + PointsToFunction_Delete(pointsToFunc); + } + return; + } + + prev = pointsToFunc; + pointsToFunc = pointsToFunc->otherPtes; + } +} + +CW_INLINE void PointsToFunction_RemoveAll(PointsToFunction *pointsToFunc) { + IRO_ASSERT(3862, pointsToFunc != NULL); + + while (pointsToFunc && pointsToFunc->pte) + PointsToFunction_RemoveByLocationSet(pointsToFunc, pointsToFunc->pte->loc); +} + +CW_INLINE void PointsToFunction_AddFunctionAction(PointsToEntry *pte, void *refcon) { + IRO_ASSERT(3872, pte != NULL); + IRO_ASSERT(3873, refcon != NULL); + + PointsToFunction_Add((PointsToFunction *) refcon, pte); +} + +CW_INLINE void PointsToFunction_SimpleAddFunctionAction(PointsToEntry *pte, void *refcon) { + IRO_ASSERT(3880, pte != NULL); + IRO_ASSERT(3881, refcon != NULL); + + PointsToFunction_SimpleAdd((PointsToFunction *) refcon, pte); +} + +CW_INLINE void PointsToFunction_AddAllIGuess_sub_487D80(PointsToFunction *dest, PointsToFunction *src) { + IRO_ASSERT(3888, dest != NULL); + IRO_ASSERT(3889, src != NULL); + + if (dest->pte) + PointsToFunction_ForEach(src, PointsToFunction_AddFunctionAction, dest); + else + PointsToFunction_ForEach(src, PointsToFunction_SimpleAddFunctionAction, dest); +} + +CW_INLINE void PointsToFunction_SortByExtendedParamNum(PointsToFunction *pointsToFunc) { + UInt32 value1; + UInt32 value2; + PointsToFunction *scan; + + while (pointsToFunc && pointsToFunc->pte) { + value1 = 0; + if (pointsToFunc->pte->loc && pointsToFunc->pte->loc->block) { + PAMemoryBlock *block = pointsToFunc->pte->loc->block; + if (block->kind == PAMEMORYBLOCKKIND_EXTENDEDPARAM && block->u.ep) { + value1 = 2 * (block->u.ep->x4) + 1; + } else if (block->kind == PAMEMORYBLOCKKIND_LOCALVAR && block->u.localvar) { + if (block->u.localvar->x0 && block->u.localvar->x0->extParam) + value1 = 2 * block->u.localvar->x0->extParam->x4; + } + } + + for (scan = pointsToFunc->otherPtes; scan && scan->pte; scan = scan->otherPtes) { + value2 = 0; + if (scan->pte->loc && scan->pte->loc->block) { + PAMemoryBlock *block = scan->pte->loc->block; + if (block->kind == PAMEMORYBLOCKKIND_EXTENDEDPARAM && block->u.ep) { + value2 = 2 * (block->u.ep->x4) + 1; + } else if (block->kind == PAMEMORYBLOCKKIND_LOCALVAR && block->u.localvar) { + if (block->u.localvar->x0 && block->u.localvar->x0->extParam) + value2 = 2 * block->u.localvar->x0->extParam->x4; + } + } + + if (value2 < value1) { + LocationSet *saveloc; + LocationSetSet *savelocs; + saveloc = pointsToFunc->pte->loc; + savelocs = pointsToFunc->pte->locs; + pointsToFunc->pte->loc = scan->pte->loc; + pointsToFunc->pte->locs = scan->pte->locs; + scan->pte->loc = saveloc; + scan->pte->locs = savelocs; + } + } + + pointsToFunc = pointsToFunc->otherPtes; + } +} + +CW_INLINE Boolean PointsToFunctions_Equal(PointsToFunction *pointsToFunc1, PointsToFunction *pointsToFunc2) { + PointsToFunction *scan; + PointsToEntry *pte; + + IRO_ASSERT(3968, pointsToFunc1 != NULL); + IRO_ASSERT(3969, pointsToFunc2 != NULL); + + if (pointsToFunc1 == pointsToFunc2) + return 1; + + for (scan = pointsToFunc1; scan && scan->pte; scan = scan->otherPtes) { + pte = PointsToFunction_FindByLocationSet(pointsToFunc2, scan->pte->loc); + if (!pte || !PointsToEntries_Equal(pte, scan->pte)) + return 0; + } + + for (scan = pointsToFunc2; scan && scan->pte; scan = scan->otherPtes) { + pte = PointsToFunction_FindByLocationSet(pointsToFunc1, scan->pte->loc); + if (!pte || !PointsToEntries_Equal(pte, scan->pte)) + return 0; + } + + return 1; +} + +CW_INLINE Boolean PointsToFunctions_Match(PointsToFunction *pointsToFunc1, PointsToFunction *pointsToFunc2) { + return 1; +} + +CW_INLINE PartialTransferFunction *PartialTransferFunction_New(void) { + PartialTransferFunction *ptf = IRO_malloc(sizeof(PartialTransferFunction)); + + IRO_ASSERT(4110, ptf != NULL); +#ifdef IRO_DEBUG + ptf->initialPointsToFn = NULL; + ptf->finalPointsToFn = NULL; + ptf->funcModifies = NULL; + ptf->context.nd = NULL; + ptf->context.ptf = NULL; + ptf->returnLocation = NULL; +#endif + return ptf; +} + +CW_INLINE void PartialTransferFunction_Delete(PartialTransferFunction *ptf) { + IRO_ASSERT(4126, ptf != NULL); + IRO_ASSERT(4127, ptf->initialPointsToFn == NULL); + IRO_ASSERT(4128, ptf->finalPointsToFn == NULL); + IRO_ASSERT(4129, ptf->funcModifies == NULL); + IRO_ASSERT(4130, ptf->context.nd == NULL); + IRO_ASSERT(4131, ptf->context.ptf == NULL); + IRO_ASSERT(4132, ptf->returnLocation == NULL); + IRO_DEBUG_CLEAR(ptf, sizeof(PartialTransferFunction)); + IRO_free(ptf); +} + +CW_INLINE void PartialTransferFunction_Init(PartialTransferFunction *ptf, IROLinear *contextNd, PartialTransferFunction *contextPTF) { + IRO_ASSERT(4142, ptf != NULL); + IRO_ASSERT(4143, contextNd != NULL); + IRO_ASSERT(4144, contextPTF != NULL); + + ptf->initialPointsToFn = PointsToFunction_New(); + PointsToFunction_Init(ptf->initialPointsToFn); + ptf->finalPointsToFn = PointsToFunction_New(); + PointsToFunction_Init(ptf->finalPointsToFn); + + ptf->funcModifies = LocationSetSet_New(); + LocationSetSet_Init(ptf->funcModifies); + LocationSetSet_AddUnknown(ptf->funcModifies, NULL, NULL, NULL); + + ptf->returnLocation = NULL; + ptf->x10 = 0; + + ptf->context.nd = contextNd; + ptf->context.ptf = contextPTF; +} + +CW_INLINE void PartialTransferFunction_Copy(PartialTransferFunction *dest, PartialTransferFunction *src) { + IRO_ASSERT(4164, src != NULL); + IRO_ASSERT(4165, dest != NULL); + + dest->initialPointsToFn = PointsToFunction_New(); + PointsToFunction_Copy(dest->initialPointsToFn, src->initialPointsToFn); + dest->finalPointsToFn = PointsToFunction_New(); + PointsToFunction_Copy(dest->finalPointsToFn, src->finalPointsToFn); + + dest->funcModifies = LocationSetSet_New(); + LocationSetSet_Copy(dest->funcModifies, src->funcModifies); + + if (src->returnLocation) { + dest->returnLocation = LocationSet_New(); + LocationSet_Copy(dest->returnLocation, src->returnLocation); + } else { + dest->returnLocation = NULL; + } + + dest->x10 = src->x10; + dest->context = src->context; +} + +CW_INLINE void PartialTransferFunction_Term(PartialTransferFunction *ptf) { + IRO_ASSERT(4190, ptf != NULL); + + PointsToFunction_Term(ptf->initialPointsToFn); + PointsToFunction_Delete(ptf->initialPointsToFn); + PointsToFunction_Term(ptf->finalPointsToFn); + PointsToFunction_Delete(ptf->finalPointsToFn); + LocationSetSet_Term(ptf->funcModifies); + LocationSetSet_Delete(ptf->funcModifies); + + if (ptf->returnLocation) { + PAMemoryBlock_Term(ptf->returnLocation->block); + PAMemoryBlock_Delete(ptf->returnLocation->block); + LocationSet_Term(ptf->returnLocation); + LocationSet_Delete(ptf->returnLocation); + ptf->returnLocation = NULL; + } + +#ifdef IRO_DEBUG + ptf->initialPointsToFn = NULL; + ptf->finalPointsToFn = NULL; + ptf->funcModifies = NULL; + ptf->context.nd = NULL; + ptf->context.ptf = NULL; +#endif +} + +CW_INLINE PointsToFunction *PartialTransferFunction_initialPointsToFn(PartialTransferFunction *ptf) { + IRO_ASSERT(4221, ptf != NULL); + + return ptf->initialPointsToFn; +} + +CW_INLINE PointsToFunction *PartialTransferFunction_finalPointsToFn(PartialTransferFunction *ptf) { + IRO_ASSERT(4227, ptf != NULL); + + return ptf->finalPointsToFn; +} + +CW_INLINE LocationSetSet *PTF_sub_48D750(PartialTransferFunction *ptf) { + IRO_ASSERT(4233, ptf != NULL); + + return ptf->funcModifies; +} + +CW_INLINE LocationSet *PartialTransferFunction_returnLocation(PartialTransferFunction *ptf) { + IRO_ASSERT(4249, ptf != NULL); + + if (!ptf->returnLocation) { + PAMemoryBlock *block; + LocationSet *ls; + + block = PAMemoryBlock_New(); + PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_LOCALVAR, NULL); + ls = LocationSet_New(); + LocationSet_InitKnown(ls, block, cint64_zero, 0, TYPE(&void_ptr)); + ptf->returnLocation = ls; + } + + return ptf->returnLocation; +} + +CW_INLINE IROLinear *PTF_sub_48B980(PartialTransferFunction *ptf) { + IRO_ASSERT(4265, ptf != NULL); + + return ptf->context.nd; +} + +CW_INLINE PartialTransferFunction *PTF_sub_48B970(PartialTransferFunction *ptf) { + IRO_ASSERT(4271, ptf != NULL); + + return ptf->context.ptf; +} + +CW_INLINE void PartialTransferFunction_sub_48A610(PartialTransferFunction *ptf, Boolean value) { + IRO_ASSERT(4298, ptf != NULL); + + ptf->x10 = (value != 0) ? 1 : 0; +} + +CW_INLINE PTFList *PTFList_New(void) { + PTFList *ptfList = IRO_malloc(sizeof(PTFList)); + + IRO_ASSERT(4393, ptfList != NULL); +#ifdef IRO_DEBUG + ptfList->ptf = NULL; + ptfList->otherPTFs = NULL; +#endif + return ptfList; +} + +CW_INLINE void PTFList_Delete(PTFList *ptfList) { + IRO_ASSERT(4405, ptfList != NULL); + IRO_ASSERT(4406, ptfList->ptf == NULL); + IRO_ASSERT(4407, ptfList->otherPTFs == NULL); + IRO_DEBUG_CLEAR(ptfList, sizeof(PTFList)); + IRO_free(ptfList); +} + +CW_INLINE void PTFList_Init(PTFList *ptfList) { + IRO_ASSERT(4417, ptfList != NULL); + + ptfList->ptf = NULL; + ptfList->otherPTFs = NULL; +} + +CW_INLINE void PTFList_Term(PTFList *ptfList) { + IRO_ASSERT(4435, ptfList != NULL); + + PTFList_RemoveAll(ptfList); + +#ifdef IRO_DEBUG + ptfList->ptf = NULL; + ptfList->otherPTFs = NULL; +#endif +} + +CW_INLINE void PTFList_ForEach(PTFList *ptfList, void (*action)(PartialTransferFunction *, void *), void *refcon) { + IRO_ASSERT(4478, ptfList != NULL); + IRO_ASSERT(4479, action != NULL); + IRO_ASSERT(4480, refcon == NULL || refcon != NULL); + + while (ptfList && ptfList->ptf) { + action(ptfList->ptf, refcon); + ptfList = ptfList->otherPTFs; + } +} + +CW_INLINE PartialTransferFunction *PTFList_sub_48A0F0(PTFList *ptfList, PartialTransferFunction *ptf) { + IRO_ASSERT(4490, ptfList != NULL); + IRO_ASSERT(4491, ptf != NULL); + + while (ptfList && ptfList->ptf) { + if (ptfList->ptf == ptf) + return ptfList->ptf; + + ptfList = ptfList->otherPTFs; + } + + return NULL; +} + +CW_INLINE PartialTransferFunction *PTFList_FindFirst(PTFList *ptfList) { + IRO_ASSERT(4502, ptfList != NULL); + + return ptfList->ptf; +} + +CW_INLINE void PTFList_sub_48A080(PTFList *ptfList, PartialTransferFunction *ptf) { + IRO_ASSERT(4511, ptfList != NULL); + IRO_ASSERT(4512, ptf != NULL); + + if (ptfList->ptf) { + PTFList *newList = PTFList_New(); + PTFList_Init(newList); + newList->ptf = ptfList->ptf; + newList->otherPTFs = ptfList->otherPTFs; + ptfList->otherPTFs = newList; + } + + ptfList->ptf = ptf; +} + +CW_INLINE void PTFList_sub_48A050(PTFList *ptfList, PartialTransferFunction *ptf) { + IRO_ASSERT(4529, ptfList != NULL); + IRO_ASSERT(4530, ptf != NULL); + + if (!PTFList_sub_48A0F0(ptfList, ptf)) + PTFList_sub_48A080(ptfList, ptf); +} + +CW_INLINE void PTFList_Remove(PTFList *ptfList, PartialTransferFunction *ptf) { + PTFList *prev; + PTFList *tmp; + + IRO_ASSERT(4542, ptfList != NULL); + IRO_ASSERT(4543, ptf != NULL); + + prev = NULL; + while (ptfList && ptfList->ptf) { + if (ptfList->ptf == ptf) { + if (!prev) { + if (ptfList->otherPTFs == NULL) { + ptfList->ptf = NULL; + } else { + tmp = ptfList->otherPTFs; + ptfList->ptf = ptfList->otherPTFs->ptf; + ptfList->otherPTFs = ptfList->otherPTFs->otherPTFs; + tmp->ptf = NULL; + tmp->otherPTFs = NULL; + PTFList_Term(tmp); + PTFList_Delete(tmp); + } + } else { + prev->otherPTFs = ptfList->otherPTFs; + ptfList->ptf = NULL; + ptfList->otherPTFs = NULL; + PTFList_Term(ptfList); + PTFList_Delete(ptfList); + } + return; + } + + prev = ptfList; + ptfList = ptfList->otherPTFs; + } +} + +CW_INLINE void PTFList_RemoveAll(PTFList *ptfList) { + IRO_ASSERT(4582, ptfList != NULL); + + while (ptfList && ptfList->ptf) + PTFList_Remove(ptfList, ptfList->ptf); +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c b/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c new file mode 100644 index 0000000..c5ad708 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c @@ -0,0 +1,593 @@ +#include "IroPropagate.h" +#include "IroCSE.h" +#include "IroDump.h" +#include "IroEval.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IROUseDef.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/objects.h" +#include "compiler/CExpr.h" +#include "compiler/CompilerTools.h" +#include "compiler/CParser.h" +#include "compiler/InlineAsm.h" +#include "compiler/InlineAsmPPC.h" + +IROAssign *IRO_FirstAssign; +IROAssign *IRO_LastAssign; +SInt32 IRO_NumAssign; + +static Boolean VarIsUsedInOtherFNodes(VarRecord *var, IRONode *node) { + if (var->defs && var->uses) { + IROUse *use; + IRODef *def = NULL; + for (use = var->uses; use; use = use->varnext) { + if (!def && use->node == node && use->linear && !(use->linear->flags & IROLF_Assigned)) { + for (def = var->defs; def; def = def->varnext) { + if (Bv_IsBitSet(def->index, use->x18)) + break; + } + } + } + + if (def) { + for (use = var->uses; use; use = use->varnext) { + if (use->node != node && use->linear && !(use->linear->flags & IROLF_Assigned)) { + if (Bv_IsBitSet(def->index, use->x18)) + return 1; + } + } + } + } else { + IROLinear *linear; + IRONode *scan; + for (scan = IRO_FirstNode; scan; scan = scan->nextnode) { + if (scan != node) { + linear = scan->first; + while (1) { + if (!linear) + break; + + if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) { + if (IRO_FindVar(linear->u.diadic.left->u.node->data.objref, 0, 1) == var) + return 1; + } + + if (linear == scan->last) + break; + linear = linear->next; + } + } + } + IRO_CheckForUserBreak(); + } + + return 0; +} + +static void GetExprUses(IROLinear *linear, Boolean isFirst) { + if (isFirst && 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))) { + VarRecord *var = IRO_FindVar(obj, 0, 1); + if (var) + Bv_SetBit(var->index, IRO_VarKills); + } + } +} + +static void GetExprKills(IROLinear *linear, Boolean isFirst) { + if (isFirst) + IRO_GetKills(linear); +} + +static void CheckUnorderedRegionForDefs(IROLinear *linear, BitVector *a, BitVector *b, Boolean *flag) { + Bv_Clear(a); + Bv_Clear(IRO_VarKills); + IRO_WalkTree(linear, GetExprKills); + Bv_Or(IRO_VarKills, a); + if (Bv_BitsInCommon(a, b)) + *flag = 1; +} + +static void CheckUnorderedRegionsForDefs(IROLinear *linear1, IROLinear *linear2, BitVector *a, BitVector *b, Boolean *flag) { + int i; + + switch (linear1->type) { + case IROLinearOp2Arg: + if (linear1->nodetype == ELAND) break; + if (linear1->nodetype == ELOR) break; + if (linear1->nodetype == ECOMMA) break; + if (linear1->u.diadic.left != linear2) + CheckUnorderedRegionForDefs(linear1->u.diadic.left, a, b, flag); + if (linear1->u.diadic.right != linear2) + CheckUnorderedRegionForDefs(linear1->u.diadic.right, a, b, flag); + break; + case IROLinearFunccall: + if (linear1->u.funccall.linear8 != linear2) + CheckUnorderedRegionForDefs(linear1->u.funccall.linear8, a, b, flag); + for (i = 0; !*flag && i < linear1->u.funccall.argCount; i++) { + if (linear1->u.funccall.args[i] != linear2) + CheckUnorderedRegionForDefs(linear1->u.funccall.args[i], a, b, flag); + } + break; + } +} + +static Boolean PropagationHasDefsInUnorderedRegions(IROLinear *a, IROLinear *b) { + Boolean flag; + IROLinear *father; + BitVector *bv1; + BitVector *bv2; + VarRecord *var; + + flag = 0; + if ((father = IRO_LocateFather(a))) { + Bv_AllocVector(&bv1, IRO_NumVars + 1); + Bv_AllocVector(&bv2, IRO_NumVars + 1); + Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1); + IRO_WalkTree(b, GetExprUses); + Bv_Or(IRO_VarKills, bv2); + var = IRO_FindVar(a->u.diadic.left->u.node->data.objref, 0, 1); + Bv_SetBit(var->index, bv2); + while (father && !flag) { + CheckUnorderedRegionsForDefs(father, a, bv1, bv2, &flag); + a = father; + father = IRO_LocateFather(father); + } + } + + return flag; +} + +int IRO_IsRegable(Object *obj) { + if (obj->datatype == DLOCAL && obj->u.var.info) + return obj->u.var.info->noregister == 0; + return 0; +} + +static Boolean IsPropagatable(IROLinear *linear) { + Object *obj; + Object *obj2; + + if (IS_LINEAR_DIADIC(linear, EASS) && (obj = IRO_IsVariable(linear->u.diadic.left)) && obj->type == linear->rtype && !is_volatile_object(obj)) { + if (linear->u.diadic.left->flags & IROLF_BitfieldIndirect) { + if (!IRO_IsConstant(linear->u.diadic.right)) + return 0; + else + return 1; + } + + if (IRO_IsConstant(linear->u.diadic.right)) + return 1; + + if ((obj2 = IRO_IsVariable(linear->u.diadic.right)) && !is_volatile_object(obj2) && IRO_TypesEqual(obj->type, linear->rtype)) { + if (!Inline_IsObjectData(linear->u.diadic.right->u.monadic->u.node->data.objref)) { + if (IRO_IsRegable(obj) && !IRO_IsRegable(obj2)) + return 0; + return 1; + } + } + } + + return 0; +} + +static Boolean IsIntGenKillCandidate(IROLinear *linear) { + if (linear->type == IROLinearFunccall) + return 1; + + if (IRO_IsAssignOp[linear->nodetype] && (linear->type == IROLinearOp1Arg || linear->type == IROLinearOp2Arg)) + return 1; + + if (linear->type == IROLinearAsm) + return 1; + + return 0; +} + +static Boolean IsPropagatableExpr(IROLinear *linear, IROList *list) { + Object *obj; + if (IS_LINEAR_DIADIC(linear, EASS) && !(linear->flags & IROLF_Reffed)) { + if ((obj = IRO_IsVariable(linear->u.diadic.left)) && !is_volatile_object(obj) && !(linear->u.diadic.left->flags & IROLF_BitfieldIndirect)) { + if (!IRO_IsRegable(obj)) + return 0; + if (IS_LINEAR_ENODE(linear->u.diadic.right, ESTRINGCONST)) + return 0; + + IRO_FindDepends(linear->u.diadic.right); + if (!IRO_NotSubable) + return 1; + } + } + + return 0; +} + +static void ClearAvailibilityOnNode(IRONode *node, UInt32 bit) { + IRONode *scan; + + for (scan = node->nextnode; scan; scan = scan->nextnode) + Bv_ClearBit(bit, scan->x16); +} + +Boolean IRO_CopyAndConstantPropagation(void) { + IROAssign *ass2; + IROAssign *ass; + IROLinear *linear; + IRONode *node; + VarRecord *var; + BitVector *bv; + Boolean flag; + Boolean result; + + IRO_FirstAssign = NULL; + IRO_NumAssign = 0; + result = 0; + + for (node = IRO_FirstNode; node; node = node->nextnode) { + linear = node->first; + while (1) { + if (!linear) + break; + + if (IsPropagatable(linear) && (var = IRO_FindAssigned(linear))) { + IROAssign *newass; + IRO_Dump("Found propagatable assignment at: %d\n", linear->index); + newass = oalloc(sizeof(IROAssign)); + newass->linear = linear; + newass->next = NULL; + newass->index = ++IRO_NumAssign; + newass->varIndex = var->index; + newass->linear2 = linear->u.diadic.right; + newass->var = NULL; + newass->varObj = IRO_IsVariable(linear->u.diadic.right); + newass->node = node; + if (newass->varObj) + newass->var = IRO_FindVar(newass->varObj, 0, 1); + if (!IRO_FirstAssign) + IRO_FirstAssign = newass; + else + IRO_LastAssign->next = newass; + IRO_LastAssign = newass; + } + + if (linear == node->last) + break; + linear = linear->next; + } + } + + IRO_CheckForUserBreak(); + + node = IRO_FirstNode; + ass = IRO_FirstAssign; + Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1); + while (node) { + Bv_AllocVector(&node->x16, IRO_NumAssign); + if (node != IRO_FirstNode) + Bv_Set(node->x16); + Bv_AllocVector(&node->x22, IRO_NumAssign); + Bv_AllocVector(&node->x1E, IRO_NumAssign); + Bv_AllocVector(&node->x2A, IRO_NumAssign); + node->x1A = NULL; + + linear = node->first; + while (1) { + if (!linear) + break; + + if (IsIntGenKillCandidate(linear)) { + //IROAssign *ass2; + Bv_Clear(IRO_VarKills); + IRO_GetKills(linear); + + for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) { + if (Bv_IsBitSet(ass2->varIndex, IRO_VarKills)) { + Bv_SetBit(ass2->index, node->x22); + Bv_ClearBit(ass2->index, node->x1E); + } + if (ass2->var && Bv_IsBitSet(ass2->var->index, IRO_VarKills)) { + Bv_SetBit(ass2->index, node->x22); + Bv_ClearBit(ass2->index, node->x1E); + } + } + } + + while (ass && ass->linear == linear) { + Bv_SetBit(ass->index, node->x1E); + ass = ass->next; + } + + if (linear == node->last) + break; + linear = linear->next; + } + + Bv_Copy(node->x16, node->x2A); + Bv_Minus(node->x22, node->x2A); + Bv_Or(node->x1E, node->x2A); + node = node->nextnode; + } + + IRO_CheckForUserBreak(); + + Bv_AllocVector(&bv, IRO_NumAssign); + do { + flag = 0; + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (node == IRO_FirstNode) { + Bv_Clear(bv); + } else { + UInt16 i; + Bv_Set(bv); + for (i = 0; i < node->numpred; i++) + Bv_And(IRO_NodeTable[node->pred[i]]->x2A, bv); + } + + if (!Bv_Compare(bv, node->x16)) { + flag = 1; + Bv_Copy(bv, node->x16); + } + + Bv_Copy(node->x16, node->x2A); + Bv_Minus(node->x22, node->x2A); + Bv_Or(node->x1E, node->x2A); + } + } while (flag); + + IRO_CheckForUserBreak(); + + node = IRO_FirstNode; + ass = IRO_FirstAssign; + while (node) { + IRO_Avail = node->x16; + linear = node->first; + while (1) { + if (!linear) + break; + + if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) { + if ((var = IRO_FindVar(linear->u.diadic.left->u.node->data.objref, 0, 1))) { + //IROAssign *ass2; + for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) { + if ( + ass2->varIndex == var->index && + Bv_IsBitSet(ass2->index, IRO_Avail) && + (IRO_IsConstant(ass2->linear2) || node->loopdepth <= ass2->node->loopdepth) && + !PropagationHasDefsInUnorderedRegions(linear, ass2->linear2) + ) { + if (ass2->linear2->type == IROLinearOperand && IRO_is_CPtypeequal(linear->rtype, ass2->linear->u.diadic.left->rtype)) { + ENode *enode = IRO_NewENode(ass2->linear2->u.node->type); + *enode = *ass2->linear2->u.node; + if (enode->type == EINTCONST) { + if (linear->flags & IROLF_BitfieldIndirect) { + IRO_TruncateBitfieldValueToType(&enode->data.intval, linear->rtype, var->x1A); + enode->rtype = linear->rtype; + result = 1; + } else { + IRO_TruncateValueToType(&enode->data.intval, linear->rtype); + enode->rtype = linear->rtype; + } + } + linear->u.monadic->type = IROLinearNop; + linear->type = IROLinearOperand; + linear->u.node = enode; + } else if (ass2->varObj && IRO_is_CPtypeequal(linear->rtype, ass2->linear->rtype)) { + linear->u.diadic.left->u.node = create_objectrefnode(ass2->varObj); + if (ass2->linear2->flags & IROLF_BitfieldIndirect) + linear->flags |= IROLF_BitfieldIndirect; + } + IRO_Dump("Found propagation at %d from %d\n", linear->index, ass2->linear->index); + break; + } + } + } + } else if (linear->type == IROLinearAsm) { + IAEffects effects; + int i; + CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects); + + for (i = 0; i < effects.numoperands; i++) { + if (effects.operands[i].type == IAEffect_0 && effects.operands[i].offset == 0 && effects.operands[i].object->type->size == effects.operands[i].size) { + if ((var = IRO_FindVar(effects.operands[i].object, 0, 1))) { + //IROAssign *ass2; + for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) { + if (ass2->varIndex == var->index && Bv_IsBitSet(ass2->index, IRO_Avail) && ass2->linear->rtype->size == effects.operands[i].size) { + ENode *enode; + if (ass2->varObj) + enode = create_objectrefnode(ass2->varObj); + else if (ass2->linear2->type == IROLinearOperand) + enode = ass2->linear2->u.node; + else + CError_FATAL(768); + CodeGen_PropagateIntoAsm(linear->u.asm_stmt, effects.operands[i].object, enode); + break; + } + } + } + } + } + } + + if (IsIntGenKillCandidate(linear)) { + //IROAssign *ass2; + Bv_Clear(IRO_VarKills); + IRO_GetKills(linear); + + for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) { + if (Bv_IsBitSet(ass2->varIndex, IRO_VarKills)) { + Bv_ClearBit(ass2->index, IRO_Avail); + } + if (ass2->var && Bv_IsBitSet(ass2->var->index, IRO_VarKills)) { + Bv_ClearBit(ass2->index, IRO_Avail); + } + } + + while (ass && ass->linear == linear) { + Bv_SetBit(ass->index, IRO_Avail); + ass = ass->next; + } + } + + if (linear == node->last) + break; + linear = linear->next; + } + node = node->nextnode; + } + + IRO_CheckForUserBreak(); + + return result; +} + +void IRO_ExpressionPropagation(void) { + IRONode *node; + IROLinear *linear; + Object *obj; + VarRecord *var; + IROAssign *ass; + + for (node = IRO_FirstNode; node; node = node->nextnode) { + IRO_FirstAssign = NULL; + IRO_LastAssign = NULL; + IRO_NumAssign = 0; + + linear = node->first; + while (1) { + IROList list; + if (!linear) + break; + + IRO_InitList(&list); + if (IsPropagatableExpr(linear, &list)) { + if ((var = IRO_FindAssigned(linear))) { + IRO_Dump("Found propagatable expression assignment at: %d\n", linear->index); + ass = oalloc(sizeof(IROAssign)); + ass->linear = linear; + ass->next = NULL; + ass->index = ++IRO_NumAssign; + ass->varIndex = var->index; + ass->linear2 = linear->u.diadic.right; + ass->x20 = 0; + ass->node = node; + IRO_FindDepends(linear->u.diadic.right); + ass->depends = IRO_Depends; + if (!IRO_FirstAssign) { + IRO_FirstAssign = ass; + ass->prev = NULL; + } else { + IRO_LastAssign->next = ass; + ass->prev = IRO_LastAssign; + } + IRO_LastAssign = ass; + } + } + + if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) { + if ((var = IRO_FindVar(linear->u.monadic->u.node->data.objref, 0, 1))) { + for (ass = IRO_LastAssign; ass; ass = ass->prev) { + if (ass->varIndex == var->index) + ass->x20++; + } + } + } + + if (linear == node->last) + break; + linear = linear->next; + } + + Bv_AllocVector(&IRO_Avail, IRO_NumAssign); + + linear = node->first; + while (1) { + if (!linear) + break; + + if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) { + if ((var = IRO_FindVar(linear->u.monadic->u.node->data.objref, 0, 1))) { + for (ass = IRO_FirstAssign; ass; ass = ass->next) { + if (ass->varIndex == var->index && Bv_IsBitSet(ass->index, IRO_Avail) && !PropagationHasDefsInUnorderedRegions(linear, ass->linear2)) { + if (ass->linear2->type == IROLinearOperand && IRO_is_CPtypeequal(linear->rtype, ass->linear->u.diadic.left->rtype)) { + ENode *enode = IRO_NewENode(ass->linear2->u.node->type); + *enode = *ass->linear2->u.node; + if (enode->type == EINTCONST) { + IRO_TruncateValueToType(&enode->data.intval, linear->rtype); + enode->rtype = linear->rtype; + } else if (enode->type == EOBJREF) { + IROLinear *tmp = IRO_LocateFather(linear); + if (tmp && (tmp->flags & IROLF_Assigned)) + linear->flags |= IROLF_Assigned; + } + linear->u.monadic->type = IROLinearNop; + linear->type = IROLinearOperand; + linear->u.node = enode; + } else if (IRO_IsVariable(ass->linear2) && IRO_is_CPtypeequal(linear->rtype, ass->linear->rtype)) { + linear->u.monadic->u.node = create_objectrefnode(ass->linear2->u.monadic->u.node->data.objref); + if (ass->linear2->flags & IROLF_BitfieldIndirect) + linear->flags |= IROLF_BitfieldIndirect; + } else if (IRO_is_CPtypeequal(linear->rtype, ass->linear->rtype) && ass->x20 == 1 && !VarIsUsedInOtherFNodes(var, node)) { + IROList list; + IRO_InitList(&list); + IRO_DuplicateExpr(ass->linear->u.diadic.right, &list); + if (IS_TYPE_FLOAT(ass->linear->rtype)) { + IROLinear *tmp = IRO_NewLinear(IROLinearOp1Arg); + tmp->index = ++IRO_NumLinear; + tmp->rtype = ass->linear->rtype; + tmp->nodetype = ETYPCON; + tmp->nodeflags = ENODE_FLAG_80; + tmp->u.monadic = list.tail; + IRO_AddToList(tmp, &list); + } + IRO_PasteAfter(list.head, list.tail, linear); + IRO_LocateFather_Cut_And_Paste(linear, list.tail); + linear = list.tail; + } + IRO_Dump("Found expression propagation at %d from %d\n", linear->index, ass->linear->index); + break; + } + } + } + } + + if (linear->type != IROLinearNop && IsIntGenKillCandidate(linear)) { + Bv_Clear(IRO_VarKills); + IRO_GetKills(linear); + for (ass = IRO_FirstAssign; ass; ass = ass->next) { + if (Bv_IsBitSet(ass->varIndex, IRO_VarKills)) + Bv_ClearBit(ass->index, IRO_Avail); + if ((obj = IRO_IsVariable(ass->linear->u.diadic.right))) { + if ((var = IRO_FindVar(obj, 0, 1))) { + if (Bv_IsBitSet(var->index, IRO_VarKills)) + Bv_ClearBit(ass->index, IRO_Avail); + } + } else { + IROList list; + IRO_InitList(&list); + IRO_Depends = ass->depends; + IRO_FindDepends_NoAlloc(ass->linear->u.diadic.right); + if (Bv_BitsInCommon(IRO_VarKills, ass->depends)) + Bv_ClearBit(ass->index, IRO_Avail); + } + } + + for (ass = IRO_FirstAssign; ass; ass = ass->next) { + IRO_Depends = ass->depends; + IRO_FindDepends_NoAlloc(ass->linear->u.diadic.right); + if (ass->linear == linear && !Bv_IsBitSet(ass->varIndex, ass->depends)) + Bv_SetBit(ass->index, IRO_Avail); + } + } + + if (linear == node->last) + break; + linear = linear->next; + } + } + + IRO_CheckForUserBreak(); +} + diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.h b/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.h new file mode 100644 index 0000000..ff9fadb --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.h @@ -0,0 +1,35 @@ +#ifndef COMPILER_IROPROPAGATE_H +#define COMPILER_IROPROPAGATE_H + +#include "IrOptimizer.h" +#include "BitVector.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +struct IROAssign { + IROLinear *linear; + UInt16 index; + UInt16 varIndex; + IROLinear *linear2; + BitVector *depends; + Object *varObj; + VarRecord *var; + IROAssign *next; + IROAssign *prev; + UInt16 x20; + IRONode *node; +}; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +extern IROAssign *IRO_FirstAssign; +extern IROAssign *IRO_LastAssign; +extern SInt32 IRO_NumAssign; + +extern int IRO_IsRegable(Object *obj); +extern Boolean IRO_CopyAndConstantPropagation(void); +extern void IRO_ExpressionPropagation(void); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c b/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c new file mode 100644 index 0000000..737035f --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c @@ -0,0 +1,774 @@ +#include "IroRangePropagation.h" +#include "IroDump.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroMalloc.h" +#include "IroPointerAnalysis.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/CInt64.h" +#include "compiler/objects.h" +#include "compiler/types.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef enum ERangeType { + ERangeType0, + ERangeType1, + ERangeType2, + ERangeType3 +} ERangeType; + +typedef struct ERange { + ERangeType type; + CInt64 upper; + CInt64 lower; +} ERange; + +typedef struct ERecord { + Object *object; + ERange *range; + struct ERecord *next; +} ERecord; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static ERecord *ERangeFirst; +static ERecord *ERangeLast; + +static ERange *ERnewERange(ERangeType type) { + ERange *range; + + range = oalloc(sizeof(ERange)); + range->type = type; + return range; +} + +static ERecord *ERnewRecord(Object *object, ERange *range) { + ERecord *record; + + record = oalloc(sizeof(ERecord)); + record->object = object; + record->range = range; + record->next = ERangeFirst; + ERangeFirst = record; + if (!ERangeLast) + ERangeLast = record; + return record; +} + +static ERecord *ERecordFound(Object *obj) { + ERecord *scan; + + scan = ERangeFirst; + while (scan && obj != scan->object) + scan = scan->next; + + return scan; +} + +static Boolean EREandHasNoUse(ERange *range, CInt64 val) { + UInt16 i; + CInt64 v11; + CInt64 work; + + i = 0; + work = range->upper; + while (CInt64_NotEqual(work = CInt64_ShrU(work, cint64_one), cint64_zero)) + i++; + + if (CInt64_NotEqual(range->upper, cint64_zero)) + i++; + + CInt64_SetULong(&work, i); + v11 = CInt64_Sub(CInt64_Shl(cint64_one, work), cint64_one); + if (CInt64_NotEqual(cint64_zero, CInt64_And(CInt64_Inv(val), v11))) + return 0; + else + return 1; +} + +static void ERcheckOverflow(ERange *range, Type *type) { + CInt64 typeSize; + CInt64 work; + CInt64 work2; + CInt64 value3; + + if (!range) + return; + + if (!IS_TYPE_INT(type)) { + range->type = ERangeType3; + return; + } + + CInt64_SetLong(&typeSize, type->size); + CInt64_SetLong(&value3, 3); + + if (IRO_IsUnsignedType(type)) { + if (type->size < 8) { + work = CInt64_Sub(CInt64_Shl(cint64_one, CInt64_Shl(typeSize, value3)), cint64_one); + if (CInt64_GreaterU(range->upper, work)) + range->type = ERangeType3; + } else { + range->type = ERangeType3; + } + } else { + if (type->size < 8) { + work = CInt64_Sub(CInt64_Shl(cint64_one, CInt64_Sub(CInt64_Shl(typeSize, value3), cint64_one)), cint64_one); + work2 = CInt64_Shl(cint64_negone, CInt64_Sub(CInt64_Shl(typeSize, value3), cint64_one)); + if (CInt64_Greater(range->upper, work) || CInt64_Less(range->lower, work2)) + range->type = ERangeType3; + } else { + range->type = ERangeType3; + } + } +} + +static void ERinvalidAll(void) { + ERecord *record; + + for (record = ERangeFirst; record; record = record->next) + record->range->type = ERangeType3; +} + +static void SetRangesForKillsByIndirectAssignment(IROLinear *nd) { + IROListNode *list; + IROListNode *scan; + IROLinear *inner; + Boolean failed; + IROListNode *resultList; + IROLinear *scannd; + Boolean foundObjRef; + ERecord *record; + ERange *range; + IROListNode *next; + Object *obj; + IROLinear *analysend; + Object *proc; + + failed = 0; + if (nd->type == IROLinearOp2Arg) + inner = nd->u.diadic.left; + else + inner = nd->u.monadic; + + if ( + inner && + inner->type == IROLinearOp1Arg && + inner->nodetype == EINDIRECT && + (analysend = inner->u.monadic) && + copts.opt_pointer_analysis && + analysend->pointsToFunction && + (proc = FunctionName) + ) { + resultList = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(proc, analysend, &resultList); + + if ((list = resultList)) { + for (scan = list; scan; scan = scan->nextList) { + if (!scan->list.head || !scan->list.tail) { + failed = 1; + break; + } + + foundObjRef = 0; + for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) { + if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) { + foundObjRef = 1; + break; + } + } + + if (!foundObjRef) { + failed = 1; + break; + } + } + + if (!failed) { + for (; list; list = list->nextList) { + for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) { + if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) { + obj = scannd->u.node->data.objref; + CError_ASSERT(302, obj != NULL); + + range = nd->x16; + if (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC) + range = inner->x16; + + record = ERecordFound(obj); + if (!record) + ERnewRecord(obj, range); + else + record->range = range; + } + } + } + } + + while (resultList) { + next = resultList->nextList; + IRO_free(resultList); + resultList = next; + } + } else { + failed = 1; + } + } else { + failed = 1; + } + + if (failed) { + ERinvalidAll(); + nd->x16 = ERnewERange(ERangeType3); + } +} + +static void InvalidateRangesForKillsByFunctionCall(IROLinear *nd) { + IROListNode *scan; + IROLinear *scannd; + Boolean failed; + Boolean foundObjRef; + IROListNode *list; + IROListNode *resultList; + ERecord *record; + IROListNode *next; + Object *obj; + IROLinear *analysend; + Object *proc; + ObjectList *olist; + ObjectList *killList; + + failed = 0; + + if ( + (analysend = nd->u.funccall.linear8) && + copts.opt_pointer_analysis && + analysend->pointsToFunction && + (proc = FunctionName) + ) { + resultList = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(proc, analysend, &resultList); + + if (resultList) { + for (scan = resultList; scan; scan = scan->nextList) { + if (!scan->list.head || !scan->list.tail) { + failed = 1; + break; + } + + foundObjRef = 0; + for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) { + if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) { + foundObjRef = 1; + obj = scannd->u.node->data.objref; + CError_ASSERT(385, obj != NULL); + + killList = NULL; + PointerAnalysis_GetFunctionKills(obj, nd, &killList); + + for (olist = killList; olist; olist = olist->next) { + if (!olist->object) { + failed = 1; + break; + } + } + + while (killList) { + olist = killList->next; + IRO_free(killList); + killList = olist; + } + + if (failed) + break; + } + } + + if (!foundObjRef) + failed = 1; + if (failed) + break; + } + + if (!failed) { + for (list = resultList; list; list = list->nextList) { + for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) { + if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) { + obj = scannd->u.node->data.objref; + killList = NULL; + PointerAnalysis_GetFunctionKills(obj, nd, &killList); + + for (olist = killList; olist; olist = olist->next) { + if ((record = ERecordFound(olist->object))) + record->range->type = ERangeType3; + } + + while (killList) { + olist = killList->next; + IRO_free(killList); + killList = olist; + } + } + } + } + } + + while (resultList) { + next = resultList->nextList; + IRO_free(resultList); + resultList = next; + } + } else { + failed = 1; + } + } else { + failed = 1; + } + + if (failed) + ERinvalidAll(); +} + +static void ERfoldOperand(IROLinear *nd) { + switch (nd->u.node->type) { + case EOBJREF: + nd->x16 = NULL; + break; + case EINTCONST: + nd->x16 = ERnewERange(ERangeType0); + nd->x16->upper = nd->x16->lower = nd->u.node->data.intval; + break; + case EFLOATCONST: + case ESTRINGCONST: + nd->x16 = ERnewERange(ERangeType0); + break; + } +} + +static Boolean ERfoldExpr(IROLinear *nd) { + ERecord *record; + ERange *range; + IROLinear *tmp; + IROLinear *inner; + Object *obj; + + switch (nd->nodetype) { + case EINDIRECT: + inner = nd->u.monadic; + if (IS_TYPE_INT(nd->rtype)) { + if (inner->type == IROLinearOperand && inner->u.node->type == EOBJREF) { + if (!inner->x16 && (obj = inner->u.node->data.objref)) { + if ((record = ERecordFound(obj))) { + inner->x16 = ERnewERange(ERangeType3); + *inner->x16 = *record->range; + } else { + inner->x16 = ERnewERange(ERangeType3); + inner->x16->upper = cint64_max; + inner->x16->lower = cint64_min; + ERnewRecord(obj, inner->x16); + } + } + nd->x16 = inner->x16; + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } else { + if (inner->type == IROLinearOperand && inner->u.node->type == EOBJREF && !inner->x16) + inner->x16 = ERnewERange(ERangeType3); + nd->x16 = ERnewERange(ERangeType3); + } + break; + case EAND: + case EANDASS: + if (IRO_IsIntConstant(nd->u.diadic.right)) { + CInt64 val = nd->u.diadic.right->u.node->data.intval; + nd->x16 = ERnewERange(ERangeType1); + nd->x16->upper = val; + nd->x16->lower = cint64_zero; + if ( + (range = nd->u.diadic.left->x16) && + range->type != ERangeType3 && + CInt64_LessEqualU(range->upper, val) && + CInt64_LessEqualU(range->lower, val) && + EREandHasNoUse(range, val) && + !IRO_HasSideEffect(nd->u.diadic.left) + ) { + IRO_Dump("eliminating redundant EAND %" PRId32 "; upperBound==0x%x, lowerBound==0x%x, Constant==0x%x\n", + nd->index, + CInt64_GetULong(&range->upper), + CInt64_GetULong(&range->upper), + CInt64_GetULong(&val) + ); + IRO_NopOut(nd->u.diadic.right); + nd->type = IROLinearNop; + nd->expr = NULL; + tmp = nd->u.diadic.left; + nd->u.diadic.left = nd->u.diadic.right; + if (!IRO_LocateFather_Cut_And_Paste(nd, tmp)) { + tmp->flags &= ~IROLF_Reffed; + if (IRO_IsVariable(tmp)) + IRO_NopOut(tmp); + } + } + } else { + if (nd->u.diadic.right->x16) { + nd->x16 = ERnewERange(ERangeType3); + *nd->x16 = *nd->u.diadic.right->x16; + } + } + ERcheckOverflow(nd->x16, nd->rtype); + break; + case ELOGNOT: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case ELAND: + case ELOR: + nd->x16 = ERnewERange(ERangeType1); + nd->x16->upper = cint64_one; + nd->x16->lower = cint64_zero; + ERcheckOverflow(nd->x16, nd->rtype); + break; + case EBINNOT: + case EFORCELOAD: + case EXOR: + case EOR: + case EXORASS: + case EORASS: + case ECOMMA: + case ETYPCON: + case EBITFIELD: + case ECOND: + case ENULLCHECK: + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + break; + case EASS: + if (IS_TYPE_INT(nd->rtype)) + nd->x16 = nd->u.diadic.right->x16; + break; + case EMUL: + case EMULV: + case EMULASS: + if (IS_TYPE_INT(nd->rtype)) { + if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 && + nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) { + nd->x16 = ERnewERange(ERangeType2); + if (IRO_IsUnsignedType(nd->rtype)) { + nd->x16->upper = CInt64_MulU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper); + nd->x16->lower = CInt64_MulU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower); + } else { + nd->x16->upper = CInt64_Mul(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper); + nd->x16->lower = CInt64_Mul(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower); + } + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } + ERcheckOverflow(nd->x16, nd->rtype); + break; + case EDIV: + case EDIVASS: + if (IS_TYPE_INT(nd->rtype)) { + if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 && + nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) { + nd->x16 = ERnewERange(ERangeType2); + if (!CInt64_IsZero(&nd->u.diadic.right->x16->lower) && !CInt64_IsZero(&nd->u.diadic.right->x16->upper)) { + if (IRO_IsUnsignedType(nd->rtype)) { + nd->x16->upper = CInt64_DivU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower); + nd->x16->lower = CInt64_DivU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper); + } else { + nd->x16->upper = CInt64_Div(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower); + nd->x16->lower = CInt64_Div(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper); + } + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } + ERcheckOverflow(nd->x16, nd->rtype); + break; + case EMODULO: + case EMODASS: + if (IS_TYPE_INT(nd->rtype)) { + if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 && + nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) { + nd->x16 = ERnewERange(ERangeType2); + if (!CInt64_IsZero(&nd->u.diadic.right->x16->lower) && !CInt64_IsZero(&nd->u.diadic.right->x16->upper)) { + if (IRO_IsUnsignedType(nd->rtype)) { + nd->x16->upper = CInt64_ModU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower); + nd->x16->lower = CInt64_ModU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper); + } else { + nd->x16->upper = CInt64_Mod(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower); + nd->x16->lower = CInt64_Mod(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper); + } + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } + ERcheckOverflow(nd->x16, nd->rtype); + break; + case EADDV: + case EADD: + case EADDASS: + if (IS_TYPE_INT(nd->rtype)) { + if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 && + nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) { + nd->x16 = ERnewERange(ERangeType2); + nd->x16->upper = CInt64_Add(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper); + nd->x16->lower = CInt64_Add(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower); + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } + ERcheckOverflow(nd->x16, nd->rtype); + break; + case ESUBV: + case ESUB: + case ESUBASS: + if (IS_TYPE_INT(nd->rtype)) { + if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 && + nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) { + nd->x16 = ERnewERange(ERangeType2); + nd->x16->upper = CInt64_Sub(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower); + nd->x16->lower = CInt64_Sub(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper); + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } + ERcheckOverflow(nd->x16, nd->rtype); + break; + case ESHL: + case ESHLASS: + if (IS_TYPE_INT(nd->rtype)) { + if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 && + nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) { + nd->x16 = ERnewERange(ERangeType2); + nd->x16->upper = CInt64_Shl(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper); + nd->x16->lower = CInt64_Shl(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower); + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } + ERcheckOverflow(nd->x16, nd->rtype); + break; + case ESHR: + case ESHRASS: + if (IS_TYPE_INT(nd->rtype)) { + if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 && + nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) { + nd->x16 = ERnewERange(ERangeType2); + if (IRO_IsUnsignedType(nd->rtype)) { + nd->x16->upper = CInt64_ShrU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower); + nd->x16->lower = CInt64_ShrU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper); + } else { + nd->x16->upper = CInt64_Shr(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower); + nd->x16->lower = CInt64_Shr(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper); + } + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } + ERcheckOverflow(nd->x16, nd->rtype); + break; + case EPOSTINC: + if (IS_TYPE_INT(nd->rtype)) { + if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) { + nd->x16 = ERnewERange(ERangeType2); + range = nd->u.monadic->x16; + *nd->x16 = *range; + range->upper = CInt64_Add(range->upper, cint64_one); + range->lower = CInt64_Add(range->lower, cint64_one); + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } + ERcheckOverflow(nd->x16, nd->rtype); + break; + case EPOSTDEC: + if (IS_TYPE_INT(nd->rtype)) { + if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) { + nd->x16 = ERnewERange(ERangeType2); + range = nd->u.monadic->x16; + *nd->x16 = *range; + range->upper = CInt64_Sub(range->upper, cint64_one); + range->lower = CInt64_Sub(range->lower, cint64_one); + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } + ERcheckOverflow(nd->x16, nd->rtype); + break; + case EPREINC: + if (IS_TYPE_INT(nd->rtype)) { + if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) { + nd->x16 = ERnewERange(ERangeType2); + range = nd->u.monadic->x16; + nd->x16->upper = CInt64_Add(range->upper, cint64_one); + nd->x16->lower = CInt64_Add(range->lower, cint64_one); + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } + ERcheckOverflow(nd->x16, nd->rtype); + break; + case EPREDEC: + if (IS_TYPE_INT(nd->rtype)) { + if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) { + nd->x16 = ERnewERange(ERangeType2); + range = nd->u.monadic->x16; + nd->x16->upper = CInt64_Sub(range->upper, cint64_one); + nd->x16->lower = CInt64_Sub(range->lower, cint64_one); + } else { + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + } + } + ERcheckOverflow(nd->x16, nd->rtype); + break; + case EMONMIN: + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + break; + case EPMODULO: + case EROTL: + case EROTR: + case EBCLR: + case EBTST: + case EBSET: + nd->x16 = ERnewERange(ERangeType3); + nd->x16->upper = cint64_max; + nd->x16->lower = cint64_min; + break; + default: + ERcheckOverflow(nd->x16, nd->rtype); + break; + } + + if ( + (nd->type == IROLinearOp1Arg || nd->type == IROLinearOp2Arg) && + IRO_IsAssignOp[nd->nodetype] && + nd->x16 && + IS_TYPE_INT(nd->rtype) + ) { + IROLinear *x = NULL; + if (nd->type == IROLinearOp2Arg) + x = nd->u.diadic.left; + else if (nd->type == IROLinearOp1Arg) + x = nd->u.monadic; + + if (x->type == IROLinearOp1Arg && + x->nodetype == EINDIRECT && + (x->u.monadic->nodetype == EINDIRECT || x->u.monadic->nodetype == EADD)) { + SetRangesForKillsByIndirectAssignment(nd); + } else { + obj = NULL; + if (x) + obj = IRO_IsVariable(x); + if (!obj) + return 0; + + range = nd->x16; + if (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC) + range = x->x16; + + record = ERecordFound(obj); + if (!record) + ERnewRecord(obj, range); + else + record->range = range; + } + } + + return nd->x16 != NULL; +} + +static Boolean ERfoldLinear(IROLinear *nd) { + nd->x16 = 0; + + switch (nd->type) { + case IROLinearNop: + case IROLinearEnd: + break; + case IROLinearOperand: + ERfoldOperand(nd); + break; + case IROLinearOp1Arg: + case IROLinearOp2Arg: + ERfoldExpr(nd); + break; + case IROLinearFunccall: + InvalidateRangesForKillsByFunctionCall(nd); + break; + case IROLinearAsm: + ERinvalidAll(); + break; + } + + return 0; +} + +Boolean IRO_RangePropagateInFNode(void) { + IRONode *fnode; + IROLinear *nd; + Boolean result; + + result = 0; + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + ERangeFirst = ERangeLast = NULL; + for (nd = fnode->first; nd != fnode->last; nd = nd->next) + ERfoldLinear(nd); + if (ERfoldLinear(nd)) + result = 1; + } + + if (result) { + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + } + + IRO_CheckForUserBreak(); + return result; +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.h b/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.h new file mode 100644 index 0000000..96888ac --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.h @@ -0,0 +1,8 @@ +#ifndef COMPILER_IRORANGEPROPAGATION_H +#define COMPILER_IRORANGEPROPAGATION_H + +#include "IrOptimizer.h" + +extern Boolean IRO_RangePropagateInFNode(void); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroSubable.c b/compiler_and_linker/FrontEnd/Optimizer/IroSubable.c new file mode 100644 index 0000000..513ac6c --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroSubable.c @@ -0,0 +1,160 @@ +#include "IroSubable.h" +#include "IroLinearForm.h" +#include "IroPropagate.h" +#include "IroUtil.h" +#include "compiler/enode.h" +#include "compiler/objects.h" +#include "compiler/types.h" + +static Boolean IsSubableOp[MAXEXPR]; + +void IRO_InitializeIsSubableOpArray(void) { + int i; + + for (i = 0; i < MAXEXPR; i++) + IsSubableOp[i] = 0; + + IsSubableOp[EPOSTINC] = 0; + IsSubableOp[EPOSTDEC] = 0; + IsSubableOp[EPREINC] = 0; + IsSubableOp[EPREDEC] = 0; + IsSubableOp[EINDIRECT] = 0; + IsSubableOp[EMONMIN] = 1; + IsSubableOp[EBINNOT] = 1; + IsSubableOp[ELOGNOT] = 1; + IsSubableOp[EFORCELOAD] = 0; + IsSubableOp[EMUL] = 1; + IsSubableOp[EMULV] = 1; + IsSubableOp[EDIV] = 1; + IsSubableOp[EMODULO] = 1; + IsSubableOp[EADDV] = 1; + IsSubableOp[ESUBV] = 1; + IsSubableOp[EADD] = 1; + IsSubableOp[ESUB] = 1; + IsSubableOp[ESHL] = 1; + IsSubableOp[ESHR] = 1; + IsSubableOp[ELESS] = 0; + IsSubableOp[EGREATER] = 0; + IsSubableOp[ELESSEQU] = 0; + IsSubableOp[EGREATEREQU] = 0; + IsSubableOp[EEQU] = 0; + IsSubableOp[ENOTEQU] = 0; + IsSubableOp[EAND] = 1; + IsSubableOp[EXOR] = 1; + IsSubableOp[EOR] = 1; + IsSubableOp[ELAND] = 0; + IsSubableOp[ELOR] = 0; + IsSubableOp[EASS] = 0; + IsSubableOp[EMULASS] = 0; + IsSubableOp[EDIVASS] = 0; + IsSubableOp[EMODASS] = 0; + IsSubableOp[EADDASS] = 0; + IsSubableOp[ESUBASS] = 0; + IsSubableOp[ESHLASS] = 0; + IsSubableOp[ESHRASS] = 0; + IsSubableOp[EANDASS] = 0; + IsSubableOp[EXORASS] = 0; + IsSubableOp[EORASS] = 0; + IsSubableOp[ECOMMA] = 0; + IsSubableOp[EPMODULO] = 0; + IsSubableOp[EROTL] = 0; + IsSubableOp[EROTR] = 0; + IsSubableOp[EBCLR] = 0; + IsSubableOp[EBTST] = 0; + IsSubableOp[EBSET] = 0; + IsSubableOp[ETYPCON] = 0; + IsSubableOp[EBITFIELD] = 0; + IsSubableOp[EINTCONST] = 0; + IsSubableOp[EFLOATCONST] = 0; + IsSubableOp[ESTRINGCONST] = 0; + IsSubableOp[ECOND] = 0; + IsSubableOp[EFUNCCALL] = 0; + IsSubableOp[EFUNCCALLP] = 0; + IsSubableOp[EOBJREF] = 0; + IsSubableOp[EMFPOINTER] = 0; + IsSubableOp[ENULLCHECK] = 0; + IsSubableOp[EPRECOMP] = 0; + IsSubableOp[ETEMP] = 0; + IsSubableOp[EARGOBJ] = 0; + IsSubableOp[ELOCOBJ] = 0; + IsSubableOp[ELABEL] = 0; + IsSubableOp[ESETCONST] = 0; + IsSubableOp[ENEWEXCEPTION] = 0; + IsSubableOp[ENEWEXCEPTIONARRAY] = 0; + IsSubableOp[EOBJLIST] = 0; + IsSubableOp[EMEMBER] = 0; + IsSubableOp[ETEMPLDEP] = 0; + IsSubableOp[EINSTRUCTION] = 0; + IsSubableOp[EDEFINE] = 0; + IsSubableOp[EREUSE] = 0; + IsSubableOp[EASSBLK] = 0; + IsSubableOp[EVECTOR128CONST] = 0; + IsSubableOp[ECONDASS] = 0; +} + +static int IsSubscript(IROLinear *nd) { + return 0; +} + +Boolean IRO_IsSubableExpression(IROLinear *nd) { + Object *varobj; + Boolean result; + + switch (nd->type) { + case IROLinearOp2Arg: + if (nd->nodetype == EADD || nd->nodetype == ESUB) { + if ( + IRO_IsConstant(nd->u.diadic.right) && + (varobj = IRO_IsVariable(nd->u.diadic.left)) && + varobj->datatype == DLOCAL && + varobj->u.var.info && + !varobj->u.var.info->noregister) + return 0; + + } + result = IsSubableOp[nd->nodetype] && !IsSubscript(nd); + return result; + case IROLinearOp1Arg: + if (IsSubableOp[nd->nodetype] && !IsSubscript(nd)) + return 1; + + if (nd->nodetype == EINDIRECT && !(nd->flags & IROLF_Assigned)) { + if (nd->flags & IROLF_Ind) { + nd = nd->u.monadic; + if (nd->type == IROLinearOperand && + nd->u.node->type == EOBJREF && + nd->u.node->data.objref->datatype == DLOCAL && + nd->u.node->data.objref->u.var.info && + !nd->u.node->data.objref->u.var.info->noregister + ) + return 0; + return 1; + } + + if (IRO_IsVariable(nd) && IRO_IsRegable(nd->u.monadic->u.node->data.objref)) + return 0; + return 1; + } else if (nd->nodetype == ETYPCON && IS_TYPE_INT(nd->rtype) && nd->rtype->size >= nd->u.monadic->rtype->size) { + return 1; + } else { + return 0; + } + case IROLinearOperand: + default: + return 0; + } +} + +Boolean IRO_IsVectorTempCandidate(IROLinear *nd) { + return + ( + nd->type == IROLinearOp1Arg || + nd->type == IROLinearOp2Arg || + nd->type == IROLinearOp3Arg || + nd->type == IROLinearOperand || + nd->type == IROLinearFunccall + ) && ( + (nd->flags & IROLF_LoopInvariant) && + !(nd->flags & IROLF_Ind) + ); +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroSubable.h b/compiler_and_linker/FrontEnd/Optimizer/IroSubable.h new file mode 100644 index 0000000..db5f860 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroSubable.h @@ -0,0 +1,10 @@ +#ifndef COMPILER_IROSUBABLE_H +#define COMPILER_IROSUBABLE_H + +#include "IrOptimizer.h" + +extern void IRO_InitializeIsSubableOpArray(void); +extern Boolean IRO_IsSubableExpression(IROLinear *nd); +extern Boolean IRO_IsVectorTempCandidate(IROLinear *nd); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroTransform.c b/compiler_and_linker/FrontEnd/Optimizer/IroTransform.c new file mode 100644 index 0000000..8a4af16 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroTransform.c @@ -0,0 +1,2794 @@ +#include "IroTransform.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CInt64.h" +#include "compiler/CIRTransform.h" +#include "compiler/CMachine.h" +#include "compiler/CPrep.h" +#include "compiler/CompilerTools.h" +#include "IroDump.h" +#include "IroLinearForm.h" +#include "IroMalloc.h" +#include "IroPointerAnalysis.h" +#include "IROUseDef.h" +#include "IroUtil.h" +#include "IroVars.h" +#include "compiler/enode.h" +#include "compiler/types.h" + +ENodeType ExprType; +ENode *IndirectRef; +Boolean FirstTime; +CInt64 OperandConst; +Object *OperandObject; +ENodeList *FirstAddend; +ENodeList *LastAddend; +static ENodeType AssignmentOp[MAXEXPR]; +static ENodeType ComplementaryOpLogical[MAXEXPR]; +static ENodeType ComplementaryOp[MAXEXPR]; + +// forward decls +static void DoDiadic(IROLinear *nd); + +static int GetTypeSize(Type *type) { + if (type->size == 1) + return 0; + if (type->size == 2) + return 1; + if (type->size == 4) + return 2; + if (type->size == 8) + return 3; + return -1; +} + +void IRO_InitializeAssignmentOpArray(void) { + int i; + + for (i = 0; i < MAXEXPR; i++) + AssignmentOp[i] = MAXEXPR; + + AssignmentOp[EPOSTINC] = MAXEXPR; + AssignmentOp[EPOSTDEC] = MAXEXPR; + AssignmentOp[EPREINC] = MAXEXPR; + AssignmentOp[EPREDEC] = MAXEXPR; + AssignmentOp[EINDIRECT] = MAXEXPR; + AssignmentOp[EMONMIN] = MAXEXPR; + AssignmentOp[EBINNOT] = MAXEXPR; + AssignmentOp[ELOGNOT] = MAXEXPR; + AssignmentOp[EFORCELOAD] = MAXEXPR; + AssignmentOp[EMUL] = EMULASS; + AssignmentOp[EMULV] = MAXEXPR; + AssignmentOp[EDIV] = EDIVASS; + AssignmentOp[EMODULO] = EMODASS; + AssignmentOp[EADDV] = MAXEXPR; + AssignmentOp[ESUBV] = MAXEXPR; + AssignmentOp[EADD] = EADDASS; + AssignmentOp[ESUB] = ESUBASS; + AssignmentOp[ESHL] = ESHLASS; + AssignmentOp[ESHR] = ESHRASS; + AssignmentOp[ELESS] = MAXEXPR; + AssignmentOp[EGREATER] = MAXEXPR; + AssignmentOp[ELESSEQU] = MAXEXPR; + AssignmentOp[EGREATEREQU] = MAXEXPR; + AssignmentOp[EEQU] = MAXEXPR; + AssignmentOp[ENOTEQU] = MAXEXPR; + AssignmentOp[EAND] = EANDASS; + AssignmentOp[EXOR] = EXORASS; + AssignmentOp[EOR] = EORASS; + AssignmentOp[ELAND] = MAXEXPR; + AssignmentOp[ELOR] = MAXEXPR; + AssignmentOp[EASS] = MAXEXPR; + AssignmentOp[EMULASS] = MAXEXPR; + AssignmentOp[EDIVASS] = MAXEXPR; + AssignmentOp[EMODASS] = MAXEXPR; + AssignmentOp[EADDASS] = MAXEXPR; + AssignmentOp[ESUBASS] = MAXEXPR; + AssignmentOp[ESHLASS] = MAXEXPR; + AssignmentOp[ESHRASS] = MAXEXPR; + AssignmentOp[EANDASS] = MAXEXPR; + AssignmentOp[EXORASS] = MAXEXPR; + AssignmentOp[EORASS] = MAXEXPR; + AssignmentOp[ECOMMA] = MAXEXPR; + AssignmentOp[EPMODULO] = MAXEXPR; + AssignmentOp[EROTL] = MAXEXPR; + AssignmentOp[EROTR] = MAXEXPR; + AssignmentOp[EBCLR] = MAXEXPR; + AssignmentOp[EBTST] = MAXEXPR; + AssignmentOp[EBSET] = MAXEXPR; + AssignmentOp[ETYPCON] = MAXEXPR; + AssignmentOp[EBITFIELD] = MAXEXPR; + AssignmentOp[EINTCONST] = MAXEXPR; + AssignmentOp[EFLOATCONST] = MAXEXPR; + AssignmentOp[ESTRINGCONST] = MAXEXPR; + AssignmentOp[ECOND] = MAXEXPR; + AssignmentOp[EFUNCCALL] = MAXEXPR; + AssignmentOp[EFUNCCALLP] = MAXEXPR; + AssignmentOp[EOBJREF] = MAXEXPR; + AssignmentOp[EMFPOINTER] = MAXEXPR; + AssignmentOp[ENULLCHECK] = MAXEXPR; + AssignmentOp[EPRECOMP] = MAXEXPR; + AssignmentOp[ETEMP] = MAXEXPR; + AssignmentOp[EARGOBJ] = MAXEXPR; + AssignmentOp[ELOCOBJ] = MAXEXPR; + AssignmentOp[ELABEL] = MAXEXPR; + AssignmentOp[ESETCONST] = MAXEXPR; + AssignmentOp[ENEWEXCEPTION] = MAXEXPR; + AssignmentOp[ENEWEXCEPTIONARRAY] = MAXEXPR; + AssignmentOp[EOBJLIST] = MAXEXPR; + AssignmentOp[EMEMBER] = MAXEXPR; + AssignmentOp[ETEMPLDEP] = MAXEXPR; + AssignmentOp[EINSTRUCTION] = MAXEXPR; + AssignmentOp[EDEFINE] = MAXEXPR; + AssignmentOp[EREUSE] = MAXEXPR; + AssignmentOp[EASSBLK] = MAXEXPR; + AssignmentOp[EVECTOR128CONST] = MAXEXPR; + AssignmentOp[ECONDASS] = MAXEXPR; +} + +void IRO_InitializeComplementaryOpArray(void) { + int i; + + for (i = 0; i < MAXEXPR; i++) + ComplementaryOp[i] = MAXEXPR; + + ComplementaryOp[EPOSTINC] = EPOSTDEC; + ComplementaryOp[EPOSTDEC] = EPOSTINC; + ComplementaryOp[EPREINC] = EPREDEC; + ComplementaryOp[EPREDEC] = EPREINC; + ComplementaryOp[EINDIRECT] = MAXEXPR; + ComplementaryOp[EMONMIN] = EMONMIN; + ComplementaryOp[EBINNOT] = EBINNOT; + ComplementaryOp[ELOGNOT] = ELOGNOT; + ComplementaryOp[EFORCELOAD] = MAXEXPR; + ComplementaryOp[EMUL] = EDIV; + ComplementaryOp[EMULV] = MAXEXPR; + ComplementaryOp[EDIV] = EMUL; + ComplementaryOp[EMODULO] = MAXEXPR; + ComplementaryOp[EADDV] = ESUBV; + ComplementaryOp[ESUBV] = EADDV; + ComplementaryOp[EADD] = ESUB; + ComplementaryOp[ESUB] = EADD; + ComplementaryOp[ESHL] = ESHR; + ComplementaryOp[ESHR] = ESHL; + ComplementaryOp[ELESS] = EGREATER; + ComplementaryOp[EGREATER] = ELESS; + ComplementaryOp[ELESSEQU] = EGREATEREQU; + ComplementaryOp[EGREATEREQU] = ELESSEQU; + ComplementaryOp[EEQU] = ENOTEQU; + ComplementaryOp[ENOTEQU] = EEQU; + ComplementaryOp[EAND] = EOR; + ComplementaryOp[EXOR] = MAXEXPR; + ComplementaryOp[EOR] = EAND; + ComplementaryOp[ELAND] = ELOR; + ComplementaryOp[ELOR] = ELAND; + ComplementaryOp[EASS] = MAXEXPR; + ComplementaryOp[EMULASS] = EDIVASS; + ComplementaryOp[EDIVASS] = EMULASS; + ComplementaryOp[EMODASS] = MAXEXPR; + ComplementaryOp[EADDASS] = ESUBASS; + ComplementaryOp[ESUBASS] = EADDASS; + ComplementaryOp[ESHLASS] = ESHRASS; + ComplementaryOp[ESHRASS] = ESHLASS; + ComplementaryOp[EANDASS] = EORASS; + ComplementaryOp[EXORASS] = MAXEXPR; + ComplementaryOp[EORASS] = EANDASS; + ComplementaryOp[ECOMMA] = MAXEXPR; + ComplementaryOp[EPMODULO] = MAXEXPR; + ComplementaryOp[EROTL] = EROTR; + ComplementaryOp[EROTR] = EROTL; + ComplementaryOp[EBCLR] = MAXEXPR; + ComplementaryOp[EBTST] = MAXEXPR; + ComplementaryOp[EBSET] = MAXEXPR; + ComplementaryOp[ETYPCON] = MAXEXPR; + ComplementaryOp[EBITFIELD] = MAXEXPR; + ComplementaryOp[EINTCONST] = MAXEXPR; + ComplementaryOp[EFLOATCONST] = MAXEXPR; + ComplementaryOp[ESTRINGCONST] = MAXEXPR; + ComplementaryOp[ECOND] = MAXEXPR; + ComplementaryOp[EFUNCCALL] = MAXEXPR; + ComplementaryOp[EFUNCCALLP] = MAXEXPR; + ComplementaryOp[EOBJREF] = MAXEXPR; + ComplementaryOp[EMFPOINTER] = MAXEXPR; + ComplementaryOp[ENULLCHECK] = MAXEXPR; + ComplementaryOp[EPRECOMP] = MAXEXPR; + ComplementaryOp[ETEMP] = MAXEXPR; + ComplementaryOp[EARGOBJ] = MAXEXPR; + ComplementaryOp[ELOCOBJ] = MAXEXPR; + ComplementaryOp[ELABEL] = MAXEXPR; + ComplementaryOp[ESETCONST] = MAXEXPR; + ComplementaryOp[ENEWEXCEPTION] = MAXEXPR; + ComplementaryOp[ENEWEXCEPTIONARRAY] = MAXEXPR; + ComplementaryOp[EOBJLIST] = MAXEXPR; + ComplementaryOp[EMEMBER] = MAXEXPR; + ComplementaryOp[ETEMPLDEP] = MAXEXPR; + ComplementaryOp[EINSTRUCTION] = MAXEXPR; + ComplementaryOp[EDEFINE] = MAXEXPR; + ComplementaryOp[EREUSE] = MAXEXPR; + ComplementaryOp[EASSBLK] = MAXEXPR; + ComplementaryOp[EVECTOR128CONST] = MAXEXPR; + ComplementaryOp[ECONDASS] = MAXEXPR; +} + +void IRO_InitializeComplementaryOpLogicalArray(void) { + int i; + + for (i = 0; i < MAXEXPR; i++) + ComplementaryOpLogical[i] = MAXEXPR; + + ComplementaryOpLogical[EPOSTINC] = MAXEXPR; + ComplementaryOpLogical[EPOSTDEC] = MAXEXPR; + ComplementaryOpLogical[EPREINC] = MAXEXPR; + ComplementaryOpLogical[EPREDEC] = MAXEXPR; + ComplementaryOpLogical[EINDIRECT] = MAXEXPR; + ComplementaryOpLogical[EMONMIN] = MAXEXPR; + ComplementaryOpLogical[EBINNOT] = MAXEXPR; + ComplementaryOpLogical[ELOGNOT] = ELOGNOT; + ComplementaryOpLogical[EFORCELOAD] = MAXEXPR; + ComplementaryOpLogical[EMUL] = MAXEXPR; + ComplementaryOpLogical[EMULV] = MAXEXPR; + ComplementaryOpLogical[EDIV] = MAXEXPR; + ComplementaryOpLogical[EMODULO] = MAXEXPR; + ComplementaryOpLogical[EADDV] = MAXEXPR; + ComplementaryOpLogical[ESUBV] = MAXEXPR; + ComplementaryOpLogical[EADD] = MAXEXPR; + ComplementaryOpLogical[ESUB] = MAXEXPR; + ComplementaryOpLogical[ESHL] = MAXEXPR; + ComplementaryOpLogical[ESHR] = MAXEXPR; + ComplementaryOpLogical[ELESS] = EGREATEREQU; + ComplementaryOpLogical[EGREATER] = ELESSEQU; + ComplementaryOpLogical[ELESSEQU] = EGREATER; + ComplementaryOpLogical[EGREATEREQU] = ELESS; + ComplementaryOpLogical[EEQU] = ENOTEQU; + ComplementaryOpLogical[ENOTEQU] = EEQU; + ComplementaryOpLogical[EAND] = MAXEXPR; + ComplementaryOpLogical[EXOR] = MAXEXPR; + ComplementaryOpLogical[EOR] = MAXEXPR; + ComplementaryOpLogical[ELAND] = ELOR; + ComplementaryOpLogical[ELOR] = ELAND; + ComplementaryOpLogical[EASS] = MAXEXPR; + ComplementaryOpLogical[EMULASS] = MAXEXPR; + ComplementaryOpLogical[EDIVASS] = MAXEXPR; + ComplementaryOpLogical[EMODASS] = MAXEXPR; + ComplementaryOpLogical[EADDASS] = MAXEXPR; + ComplementaryOpLogical[ESUBASS] = MAXEXPR; + ComplementaryOpLogical[ESHLASS] = MAXEXPR; + ComplementaryOpLogical[ESHRASS] = MAXEXPR; + ComplementaryOpLogical[EANDASS] = MAXEXPR; + ComplementaryOpLogical[EXORASS] = MAXEXPR; + ComplementaryOpLogical[EORASS] = MAXEXPR; + ComplementaryOpLogical[ECOMMA] = MAXEXPR; + ComplementaryOpLogical[EPMODULO] = MAXEXPR; + ComplementaryOpLogical[EROTL] = MAXEXPR; + ComplementaryOpLogical[EROTR] = MAXEXPR; + ComplementaryOpLogical[EBCLR] = MAXEXPR; + ComplementaryOpLogical[EBTST] = MAXEXPR; + ComplementaryOpLogical[EBSET] = MAXEXPR; + ComplementaryOpLogical[ETYPCON] = MAXEXPR; + ComplementaryOpLogical[EBITFIELD] = MAXEXPR; + ComplementaryOpLogical[EINTCONST] = MAXEXPR; + ComplementaryOpLogical[EFLOATCONST] = MAXEXPR; + ComplementaryOpLogical[ESTRINGCONST] = MAXEXPR; + ComplementaryOpLogical[ECOND] = MAXEXPR; + ComplementaryOpLogical[EFUNCCALL] = MAXEXPR; + ComplementaryOpLogical[EFUNCCALLP] = MAXEXPR; + ComplementaryOpLogical[EOBJREF] = MAXEXPR; + ComplementaryOpLogical[EMFPOINTER] = MAXEXPR; + ComplementaryOpLogical[ENULLCHECK] = MAXEXPR; + ComplementaryOpLogical[EPRECOMP] = MAXEXPR; + ComplementaryOpLogical[ETEMP] = MAXEXPR; + ComplementaryOpLogical[EARGOBJ] = MAXEXPR; + ComplementaryOpLogical[ELOCOBJ] = MAXEXPR; + ComplementaryOpLogical[ELABEL] = MAXEXPR; + ComplementaryOpLogical[ESETCONST] = MAXEXPR; + ComplementaryOpLogical[ENEWEXCEPTION] = MAXEXPR; + ComplementaryOpLogical[ENEWEXCEPTIONARRAY] = MAXEXPR; + ComplementaryOpLogical[EOBJLIST] = MAXEXPR; + ComplementaryOpLogical[EMEMBER] = MAXEXPR; + ComplementaryOpLogical[ETEMPLDEP] = MAXEXPR; + ComplementaryOpLogical[EINSTRUCTION] = MAXEXPR; + ComplementaryOpLogical[EDEFINE] = MAXEXPR; + ComplementaryOpLogical[EREUSE] = MAXEXPR; + ComplementaryOpLogical[EASSBLK] = MAXEXPR; + ComplementaryOpLogical[EVECTOR128CONST] = MAXEXPR; + ComplementaryOpLogical[ECONDASS] = MAXEXPR; +} + +static void DoTransformations(IROLinear *nd) { + IROLinear *nd2; + IROLinear *nd3; + IROLinear *nd4; + IROLinear *nd5; + Type *newtype; + SInt32 value; + + if (nd->type == IROLinearOp2Arg) { + switch (nd->nodetype) { + case EASS: + nd2 = nd->u.diadic.right; + if ( + nd2->type == IROLinearOp2Arg && + AssignmentOp[nd2->nodetype] < MAXEXPR && + IRO_TypesEqual(nd->rtype, nd2->rtype) && + IRO_IsVariable(nd3 = nd->u.diadic.left) && + !(nd3->flags & IROLF_BitfieldIndirect) && + IRO_ExprsSame(nd3, nd2->u.diadic.left) + ) + { + nd->nodetype = AssignmentOp[nd2->nodetype]; + nd->u.diadic.right = nd2->u.diadic.right; + IRO_NopOut(nd2->u.diadic.left); + nd2->type = IROLinearNop; + + nd3->flags |= IROLF_Used; + nd3->u.diadic.left->flags |= IROLF_Used; + } + break; + + case EMUL: + if ( + IS_TYPE_INT(nd->rtype) && + IRO_IsPow2(nd->u.diadic.right, &value) + ) + { + nd->nodetype = ESHL; + CInt64_SetLong(&nd->u.diadic.right->u.node->data.intval, value); + } + break; + + case EDIV: + if ( + IS_TYPE_INT(nd->rtype) && + IRO_IsPow2(nd->u.diadic.right, &value) + ) + { + if (IRO_IsUnsignedType(nd->rtype)) { + nd->nodetype = ESHR; + CInt64_SetLong(&nd->u.diadic.right->u.node->data.intval, value); + } else if ( + !IRO_IsUnsignedType(nd->rtype) && + TYPE_INTEGRAL(nd->rtype)->integral != IT_BOOL && + nd->u.diadic.left->nodetype == ETYPCON && + IS_TYPE_INT(nd->u.diadic.left->u.monadic->rtype) && + IRO_IsUnsignedType(nd->u.diadic.left->u.monadic->rtype) && + nd->u.diadic.left->u.monadic->rtype->size < nd->u.diadic.left->rtype->size + ) + { + nd->nodetype = ESHR; + CInt64_SetLong(&nd->u.diadic.right->u.node->data.intval, value); + if (nd->flags & IROLF_Reffed) { + IROLinear *copy = IRO_NewLinear(IROLinearOp1Arg); + memcpy(copy, nd, sizeof(IROLinear)); + copy->type = IROLinearOp1Arg; + copy->nodetype = ETYPCON; + copy->index = IRO_NumLinear++; + copy->rtype = nd->rtype; + IRO_PasteAfter(copy, copy, nd); + IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, copy); + copy->u.monadic = nd; + nd->flags |= IROLF_Reffed; + } + nd->rtype = IRO_UnsignedType(nd->rtype); + newtype = IRO_UnsignedType(nd->u.diadic.right->rtype); + nd->u.diadic.right->u.node->rtype = newtype; + nd->u.diadic.right->rtype = newtype; + nd->u.diadic.left->rtype = IRO_UnsignedType(nd->u.diadic.left->rtype); + } + } + break; + + case EMODULO: + if ( + IS_TYPE_INT(nd->rtype) && + IRO_IsUnsignedType(nd->rtype) && + IRO_IsPow2(nd->u.diadic.right, &value) + ) + { + nd->nodetype = EAND; + nd->u.diadic.right->u.node->data.intval = CInt64_Sub(nd->u.diadic.right->u.node->data.intval, cint64_one); + } + break; + + case EEQU: + if ( + (nd2 = IRO_LocateFather(nd)) && + nd2->nodetype == ETYPCON && + IS_TYPE_INT(nd2->rtype) && + (nd3 = IRO_LocateFather(nd2)) && + nd3->nodetype == ELOGNOT && + (nd4 = IRO_LocateFather(nd3)) && + nd4->nodetype == ETYPCON && + IS_TYPE_INT(nd4->rtype) && + ( + ((nd5 = IRO_LocateFather(nd4)) && nd5->type == IROLinearIf) || + nd5->type == IROLinearIfNot + ) + ) + { + IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd4, nd); + nd->nodetype = ENOTEQU; + nd2->type = IROLinearNop; + nd3->type = IROLinearNop; + nd4->type = IROLinearNop; + } + break; + } + } +} + +static void IRO_SwitchChildren(IROLinear *nd) { + IROLinear *tmp = nd->u.diadic.left; + nd->u.diadic.left = nd->u.diadic.right; + nd->u.diadic.right = tmp; +} + +static void ReplaceExprWithConst(IROLinear *nd, CInt64 val) { + IRO_NopOut(nd); + nd->type = IROLinearOperand; + nd->nodetype = EINTCONST; + nd->u.node = IRO_NewENode(EINTCONST); + nd->u.node->data.intval = val; + nd->u.node->flags = nd->nodeflags; + nd->u.node->rtype = nd->rtype; + + if (IS_TYPE_FLOAT(nd->rtype)) { + nd->u.node->type = EFLOATCONST; + nd->nodetype = EFLOATCONST; + nd->u.node->data.floatval = CMach_CalcFloatConvertFromInt(TYPE(&stsignedlong), val); + } +} + +static void ReplaceExprWithLeftChild(IROLinear *nd) { + IROLinear *left = nd->u.diadic.left; + IROLinear *right = nd->u.diadic.right; + + if (left->rtype == nd->rtype) { + IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, left); + left->flags = nd->flags; + left->nodeflags = nd->nodeflags; + nd->type = IROLinearNop; + IRO_NopOut(right); + } else { + nd->type = IROLinearOp1Arg; + nd->nodetype = ETYPCON; + nd->u.monadic = left; + IRO_NopOut(right); + } +} + +static void ReplaceExprWithRightChild(IROLinear *nd) { + IROLinear *left = nd->u.diadic.left; + IROLinear *right = nd->u.diadic.right; + + if (right->rtype == nd->rtype) { + IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, right); + right->flags = nd->flags; + right->nodeflags = nd->nodeflags; + nd->type = IROLinearNop; + IRO_NopOut(left); + } else { + nd->type = IROLinearOp1Arg; + nd->nodetype = ETYPCON; + nd->u.monadic = right; + IRO_NopOut(left); + } +} + +static void ReplaceExprWithMonaminRight(IROLinear *nd) { + IROLinear *left = nd->u.diadic.left; + IROLinear *right = nd->u.diadic.right; + + if (right->rtype == nd->rtype) { + nd->type = IROLinearOp1Arg; + nd->nodetype = EMONMIN; + nd->u.monadic = right; + IRO_NopOut(left); + } else { + IRO_NopOut(left); + left->type = IROLinearOp1Arg; + left->nodetype = ETYPCON; + left->expr = right->expr; + left->rtype = nd->rtype; + left->u.monadic = right; + nd->type = IROLinearOp1Arg; + nd->nodetype = EMONMIN; + nd->u.monadic = left; + } +} + +static void ReplaceExprWithMonaminLeft(IROLinear *nd) { + IROLinear *left = nd->u.diadic.left; + IROLinear *right = nd->u.diadic.right; + + if (left->rtype == nd->rtype) { + nd->type = IROLinearOp1Arg; + nd->nodetype = EMONMIN; + nd->u.monadic = left; + IRO_NopOut(right); + } else { + IRO_NopOut(right); + right->type = IROLinearOp1Arg; + right->nodetype = ETYPCON; + right->expr = left->expr; + right->rtype = nd->rtype; + right->u.monadic = left; + nd->type = IROLinearOp1Arg; + nd->nodetype = EMONMIN; + nd->u.monadic = right; + } +} + +static void switchFatherLeftMonadic(IROLinear *nd) { + IROLinear *inner = nd->u.monadic; + IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, inner); + nd->u.monadic = inner->u.monadic; + inner->u.monadic = nd; + inner->rtype = nd->rtype; + inner->flags = nd->flags; + inner->nodeflags = nd->nodeflags; + IRO_CutAndPasteAfter(inner, inner, nd); +} + +static void switchFatherLeft(IROLinear *nd, int isRight) { + IROLinear *a; + IROLinear *b; + + a = nd->u.diadic.left; + IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, a); + + if (isRight) { + nd->u.diadic.left = a->u.diadic.left; + a->u.diadic.left = nd; + b = a->u.diadic.right; + } else { + nd->u.diadic.left = a->u.diadic.right; + a->u.diadic.right = nd; + b = a->u.diadic.left; + } + + a->rtype = nd->rtype; + a->flags = nd->flags; + a->nodeflags = nd->nodeflags; + IRO_CutAndPasteAfter(a, a, nd); + IRO_CutAndPasteAfter(IRO_FindFirst(b), b, nd); +} + +static void PickCommonsubAtLeftLeft(IROLinear *nd) { + switchFatherLeft(nd, 0); + ReplaceExprWithRightChild(nd->u.diadic.right); +} + +static void PickCommonsubAtRightLeft(IROLinear *nd) { + switchFatherLeft(nd, 1); + ReplaceExprWithRightChild(nd->u.diadic.right); +} + +static void PickCommonsubAtLeftRight(IROLinear *nd) { + switchFatherLeft(nd, 0); + ReplaceExprWithLeftChild(nd->u.diadic.right); +} + +static void PickCommonsubAtRightRight(IROLinear *nd) { + switchFatherLeft(nd, 1); + ReplaceExprWithLeftChild(nd->u.diadic.right); +} + +static void DoTransformations11(IROLinear *nd) { + IROLinear *left; + IROLinear *right; + int changed; + int compare; + Type *type; + SInt32 tmp1; + SInt32 tmp2; + CInt64 val; + + if (nd->type == IROLinearOp2Arg) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype)) + return; + + changed = 0; + if (!IRO_HasSideEffect(left) && !IRO_HasSideEffect(right)) { + if (IRO_IsIntConstant(right) || IRO_IsFloatConstant(right)) { + if (IRO_IsConstantZero(right)) { + switch (nd->nodetype) { + case EADDV: + case ESUBV: + case EADD: + case ESUB: + case ESHL: + case ESHR: + case EXOR: + case EOR: + case ELOR: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EXORASS: + case EORASS: + ReplaceExprWithLeftChild(nd); + changed = 1; + break; + case EMUL: + case EAND: + case ELAND: + ReplaceExprWithConst(nd, cint64_zero); + changed = 1; + break; + case EMULASS: + case EANDASS: + nd->nodetype = EASS; + nd->u.diadic.right->rtype = nd->rtype; + nd->u.diadic.right->u.node->rtype = nd->rtype; + changed = 1; + break; + case EDIV: + case EMODULO: + case EDIVASS: + case EMODASS: + if (nd->stmt->sourceoffset) { + TStreamElement *token = CPrep_CurStreamElement(); + token->tokenoffset = nd->stmt->sourceoffset; + CError_SetErrorToken(token); + } + CError_Warning(CErrorStr139); + break; + } + } else if (nd->nodetype == ELAND) { + ReplaceExprWithLeftChild(nd); + changed = 1; + } else if (nd->nodetype == ELOR) { + ReplaceExprWithConst(nd, cint64_one); + changed = 1; + } else if (nd->nodetype == ESHL || nd->nodetype == ESHR || nd->nodetype == ESHLASS || nd->nodetype == ESHRASS) { + type = nd->rtype; + tmp1 = type->size * 8; + if (left->type == IROLinearOp1Arg && left->nodetype == ETYPCON) { + type = left->u.monadic->rtype; + if ( + left->u.monadic->type == IROLinearOp1Arg && + left->u.monadic->nodetype == EINDIRECT && + left->u.monadic->u.monadic->type == IROLinearOp1Arg && + left->u.monadic->u.monadic->nodetype == EBITFIELD && + IS_TYPE_BITFIELD(left->u.monadic->u.monadic->rtype) + ) + tmp2 = TYPE_BITFIELD(left->u.monadic->u.monadic->rtype)->bitlength; + else + tmp2 = type->size * 8; + } else { + tmp2 = tmp1; + } + + switch (nd->nodetype) { + case ESHL: + case ESHLASS: + CInt64_SetLong(&val, tmp1); + if (IRO_IsUnsignedType(type)) + compare = CInt64_GreaterEqualU(right->u.node->data.intval, val); + else + compare = CInt64_GreaterEqual(right->u.node->data.intval, val); + break; + case ESHR: + case ESHRASS: + CInt64_SetLong(&val, tmp2); + compare = IRO_IsUnsignedType(type) && CInt64_GreaterEqualU(right->u.node->data.intval, val); + break; + } + + if (compare) { + switch (nd->nodetype) { + case ESHL: + case ESHR: + ReplaceExprWithConst(nd, cint64_zero); + break; + case ESHLASS: + case ESHRASS: + nd->nodetype = EASS; + ReplaceExprWithConst(right, cint64_zero); + break; + } + changed = 1; + } + } else if (IRO_IsConstantOne(right)) { + switch (nd->nodetype) { + case EMUL: + case EMULV: + case EDIV: + case EMULASS: + case EDIVASS: + ReplaceExprWithLeftChild(nd); + changed = 1; + break; + case EMODULO: + ReplaceExprWithConst(nd, cint64_zero); + changed = 1; + break; + case EMODASS: + nd->nodetype = EASS; + ReplaceExprWithConst(right, cint64_zero); + nd->u.diadic.right->rtype = nd->rtype; + nd->u.diadic.right->u.node->rtype = nd->rtype; + changed = 1; + break; + } + } else if (IRO_IsConstantNegativeOne(right)) { + switch (nd->nodetype) { + case EMUL: + case EMULV: + case EDIV: + ReplaceExprWithMonaminLeft(nd); + changed = 1; + break; + case EMODULO: + ReplaceExprWithConst(nd, cint64_zero); + changed = 1; + break; + case EMODASS: + nd->nodetype = EASS; + ReplaceExprWithConst(right, cint64_zero); + nd->u.diadic.right->rtype = nd->rtype; + nd->u.diadic.right->u.node->rtype = nd->rtype; + changed = 1; + break; + } + } + } + + if (!changed && (IRO_IsIntConstant(left) || IRO_IsFloatConstant(left))) { + if (IRO_IsConstantZero(left)) { + switch (nd->nodetype) { + case EADDV: + case EADD: + case EXOR: + case EOR: + case ELOR: + ReplaceExprWithRightChild(nd); + break; + case EMUL: + case ESHL: + case ESHR: + case EAND: + case ELAND: + ReplaceExprWithConst(nd, cint64_zero); + break; + case ESUBV: + case ESUB: + ReplaceExprWithMonaminRight(nd); + break; + } + } else if (nd->nodetype == ELAND) { + ReplaceExprWithRightChild(nd); + } else if (nd->nodetype == ELOR) { + ReplaceExprWithConst(nd, cint64_one); + } else if (IRO_IsConstantOne(left)) { + switch (nd->nodetype) { + case EMUL: + case EMULV: + ReplaceExprWithRightChild(nd); + break; + } + } else if (IRO_IsConstantNegativeOne(left)) { + switch (nd->nodetype) { + case EMUL: + case EMULV: + ReplaceExprWithMonaminRight(nd); + break; + } + } + } + } + } +} + +static void DoTransformations12(IROLinear *nd) { + IROLinear *left; + IROLinear *right; + + if (nd->type == IROLinearOp2Arg) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype)) + return; + + if (IRO_ExprsSameSemantically(left, right) && !IRO_HasSideEffect(left)) { + switch (nd->nodetype) { + case ESUBV: + case ESUB: + case ELESS: + case EGREATER: + case ENOTEQU: + case EXOR: + ReplaceExprWithConst(nd, cint64_zero); + break; + case ELESSEQU: + case EGREATEREQU: + case EEQU: + ReplaceExprWithConst(nd, cint64_one); + break; + case EAND: + case EOR: + case ELAND: + case ELOR: + case EASS: + case EANDASS: + case EORASS: + ReplaceExprWithLeftChild(nd); + break; + case ESUBASS: + case EXORASS: + nd->nodetype = EASS; + ReplaceExprWithConst(right, cint64_zero); + break; + } + } + } +} + +static void DoTransformations13(IROLinear *nd) { + IROLinear *left; + IROLinear *right; + IROLinear *left2; + IROLinear *right2; + IROListNode *tmp; + IROListNode *leftlist; + IROListNode *rightlist; + + if (nd->type == IROLinearOp2Arg) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + + if ( + !IRO_HasSideEffect(left) && + !IRO_HasSideEffect(right) && + (nd->nodetype == EEQU || nd->nodetype == ENOTEQU) && + PointerAnalysis_IsLinearNodePointerExprDefinite(FunctionName, left) && + PointerAnalysis_IsLinearNodePointerExprDefinite(FunctionName, right) + ) + { + leftlist = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, left, &leftlist); + if (leftlist) { + if (leftlist->list.head && leftlist->list.tail && !leftlist->nextList) { + rightlist = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, right, &rightlist); + if (rightlist) { + if (rightlist->list.head && rightlist->list.tail && !rightlist->nextList) { + left2 = leftlist->list.tail; + right2 = rightlist->list.tail; + if (IRO_ExprsSameSemantically(left2, right2)) { + ReplaceExprWithConst(nd, (nd->nodetype == EEQU) ? cint64_one : cint64_zero); + } else if (left2->type == right2->type && IRO_TypesEqual(left2->rtype, right2->rtype)) { + ReplaceExprWithConst(nd, (nd->nodetype == EEQU) ? cint64_zero : cint64_one); + } + } + + while (rightlist) { + tmp = rightlist->nextList; + IRO_free(rightlist); + rightlist = tmp; + } + } + } + + while (leftlist) { + tmp = leftlist->nextList; + IRO_free(leftlist); + leftlist = tmp; + } + } + } + } +} + +static void DoTransformations21(IROLinear *nd) { + IROLinear *left; + IROLinear *right; + Boolean changed; + + if (nd->type == IROLinearOp2Arg) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + + if (left->type == IROLinearOp1Arg && right->type == IROLinearOp1Arg && left->nodetype == right->nodetype) { + switch (left->nodetype) { + case EMONMIN: + case EBINNOT: + case ELOGNOT: + changed = 0; + switch (nd->nodetype) { + case EXOR: + if (left->nodetype == EBINNOT) + goto collapse; + break; + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + if (left->nodetype == EMONMIN) { + nd->nodetype = ComplementaryOp[nd->nodetype]; + goto collapse; + } + break; + case EMUL: + case EDIV: + if (left->nodetype == EMONMIN) + goto collapse; + break; + case EEQU: + case ENOTEQU: + if (left->nodetype != ELOGNOT) { + collapse: + nd->u.diadic.left = left->u.monadic; + nd->u.diadic.right = right->u.monadic; + left->type = right->type = IROLinearNop; + changed = 1; + } + break; + case ELAND: + case ELOR: + if (left->nodetype == ELOGNOT) { + nd->nodetype = ComplementaryOp[nd->nodetype]; + goto switchfather; + } + break; + case EAND: + case EOR: + if ( + !IS_TYPE_FLOAT(nd->rtype) && + !IS_TYPE_FLOAT(left->rtype) && + !IS_TYPE_FLOAT(right->rtype) && + left->nodetype != EMONMIN + ) + { + nd->nodetype = ComplementaryOp[nd->nodetype]; + goto switchfather; + } + break; + case EADD: + case ESUB: + if ( + !IS_TYPE_FLOAT(nd->rtype) && + !IS_TYPE_FLOAT(left->rtype) && + !IS_TYPE_FLOAT(right->rtype) && + left->nodetype == EMONMIN + ) + { + switchfather: + switchFatherLeftMonadic(nd); + nd->u.diadic.right = right->u.monadic; + right->type = IROLinearNop; + changed = 1; + } + break; + } + + if (changed) { + DoTransformations(nd); + DoTransformations11(nd); + DoTransformations12(nd); + DoTransformations13(nd); + } + break; + } + } + } +} + +static void DoTransformations22(IROLinear *nd) { + IROLinear *left; + IROLinear *right; + IROLinear *ndtmp; + + if (nd->type == IROLinearOp2Arg) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype)) + return; + + if (!IRO_HasSideEffect(left) && !IRO_HasSideEffect(right)) { + if (left->type == IROLinearOp1Arg && left->nodetype == EMONMIN) { + switch (nd->nodetype) { + case ESUB: + case ESUBV: + nd->nodetype = ComplementaryOp[nd->nodetype]; + switchFatherLeftMonadic(nd); + break; + + case EADD: + case EADDV: + nd->nodetype = ComplementaryOp[nd->nodetype]; + nd->u.diadic.left = right; + nd->u.diadic.right = left->u.monadic; + left->type = IROLinearNop; + DoTransformations(nd); + DoTransformations12(nd); + DoTransformations21(nd); + break; + + case EDIV: + if (IRO_ExprsSameSemantically(left->u.monadic, right)) + ReplaceExprWithConst(nd, cint64_negone); + break; + } + } else { + ndtmp = NULL; + if (left->type == IROLinearOp1Arg && IRO_ExprsSameSemantically(left->u.monadic, right)) + ndtmp = left; + else if (right->type == IROLinearOp1Arg && IRO_ExprsSameSemantically(left, right->u.monadic)) + ndtmp = right; + + if (ndtmp) { + switch (nd->nodetype) { + case EAND: + if (ndtmp->nodetype == EBINNOT || ndtmp->nodetype == ELOGNOT) + ReplaceExprWithConst(nd, cint64_zero); + break; + + case EANDASS: + if (ndtmp->nodetype == EBINNOT || ndtmp->nodetype == ELOGNOT) { + nd->nodetype = EASS; + ReplaceExprWithConst(right, cint64_zero); + nd->u.diadic.right->rtype = nd->rtype; + nd->u.diadic.right->u.node->rtype = nd->rtype; + } + break; + + case EXOR: + case EOR: + if (ndtmp->nodetype == EBINNOT) { + ReplaceExprWithConst(nd, cint64_zero); + nd->u.node->data.intval = CInt64_Inv(nd->u.node->data.intval); + } + break; + + case EXORASS: + case EORASS: + if (ndtmp->nodetype == EBINNOT) { + nd->nodetype = EASS; + ReplaceExprWithConst(right, cint64_zero); + right->u.node->data.intval = CInt64_Inv(right->u.node->data.intval); + nd->u.diadic.right->rtype = nd->rtype; + nd->u.diadic.right->u.node->rtype = nd->rtype; + } + break; + + case ELOR: + if (ndtmp->nodetype == EBINNOT || ndtmp->nodetype == ELOGNOT) + ReplaceExprWithConst(nd, cint64_one); + break; + + case ELAND: + if (ndtmp->nodetype == ELOGNOT) + ReplaceExprWithConst(nd, cint64_zero); + break; + + case EDIV: + if (ndtmp->nodetype == EMONMIN) + ReplaceExprWithConst(nd, cint64_negone); + break; + + case EDIVASS: + if (ndtmp->nodetype == EMONMIN) { + nd->nodetype = EASS; + ReplaceExprWithConst(right, cint64_negone); + nd->u.diadic.right->rtype = nd->rtype; + nd->u.diadic.right->u.node->rtype = nd->rtype; + } + break; + } + } + } + } + } +} + +static void DoTransformations23(IROLinear *nd) { + Boolean changed; + Boolean isCompare; + UInt8 which; + IROLinear *left; + IROLinear *right; + CInt64 size; + CInt64 val; + + if (nd->type == IROLinearOp2Arg && !IRO_HasSideEffect(nd)) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype)) + return; + + isCompare = 0; + changed = 0; + which = 0; + + switch (nd->nodetype) { + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + isCompare = 1; + case EADDV: + case EADD: + case EEQU: + case ENOTEQU: + case EAND: + case EOR: + if (left->type == IROLinearOp2Arg) { + if (IRO_ExprsSameSemantically(right, left->u.diadic.left)) + which = 1; + else if (IRO_ExprsSameSemantically(right, left->u.diadic.right)) + which = 2; + + if (which) { + if (isCompare) + nd->nodetype = ComplementaryOp[nd->nodetype]; + IRO_SwitchChildren(nd); + left = nd->u.diadic.left; + right = nd->u.diadic.right; + break; + } + } + case ESUBV: + case ESUB: + case EADDASS: + case ESUBASS: + case EANDASS: + case EORASS: + if (right->type == IROLinearOp2Arg) { + if (IRO_ExprsSameSemantically(left, right->u.diadic.left)) + which = 1; + else if (IRO_ExprsSameSemantically(left, right->u.diadic.right)) + which = 2; + } + break; + + default: + goto done; + } + + if (which) { + switch (right->nodetype) { + case EAND: + case EOR: + if (which == 2) + IRO_SwitchChildren(right); + + if ( + nd->nodetype == right->nodetype || + (nd->nodetype == EANDASS && right->nodetype == EAND) || + (nd->nodetype == EORASS && right->nodetype == EOR) + ) + { + ReplaceExprWithRightChild(right); + changed = 1; + } + else if ( + nd->nodetype == ComplementaryOp[right->nodetype] || + (nd->nodetype == EANDASS && right->nodetype == EOR) || + (nd->nodetype == EORASS && right->nodetype == EAND) + ) + { + ReplaceExprWithLeftChild(nd); + } + break; + + case EADD: + if (which == 2) + IRO_SwitchChildren(right); + + switch (nd->nodetype) { + case EEQU: + case ENOTEQU: + ReplaceExprWithConst(left, cint64_zero); + ReplaceExprWithRightChild(right); + IRO_SwitchChildren(nd); + if (isCompare) + nd->nodetype = ComplementaryOp[nd->nodetype]; + changed = 1; + break; + + case ESUB: + case ESUBV: + ReplaceExprWithRightChild(right); + ReplaceExprWithMonaminRight(nd); + changed = 1; + break; + + case ESUBASS: + ReplaceExprWithRightChild(right); + changed = 1; + break; + } + break; + + case ESUB: + switch (nd->nodetype) { + case EEQU: + case ENOTEQU: + if (which == 1) { + ReplaceExprWithConst(left, cint64_zero); + ReplaceExprWithRightChild(right); + IRO_SwitchChildren(nd); + } + break; + case EADD: + case EADDV: + if (which == 2) { + ReplaceExprWithLeftChild(right); + ReplaceExprWithRightChild(nd); + } + break; + case ESUB: + case ESUBV: + if (which == 1) { + ReplaceExprWithRightChild(right); + ReplaceExprWithRightChild(nd); + } + break; + case EADDASS: + if (which == 2) { + nd->nodetype = EASS; + ReplaceExprWithLeftChild(right); + changed = 1; + } + break; + case ESUBASS: + if (which == 1) { + nd->nodetype = EASS; + ReplaceExprWithRightChild(right); + changed = 1; + } + break; + } + break; + } + } + + done: + if (!changed) { + switch (nd->nodetype) { + case ESUB: + case ESUBV: + which = 0; + if (left->type == IROLinearOp2Arg) { + if (IRO_ExprsSameSemantically(right, left->u.diadic.left)) + which = 1; + else if (IRO_ExprsSameSemantically(right, left->u.diadic.right)) + which = 2; + } + + if (which == 1) { + if (left->nodetype == ESUB) { + ReplaceExprWithMonaminRight(left); + ReplaceExprWithLeftChild(nd); + } else if (left->nodetype == EADD) { + ReplaceExprWithRightChild(left); + ReplaceExprWithLeftChild(nd); + } + } else if (which == 2) { + if (left->nodetype == EADD) { + ReplaceExprWithLeftChild(left); + ReplaceExprWithLeftChild(nd); + } + } + break; + } + + switch (nd->nodetype) { + case ESHL: + case ESHR: + case ESHLASS: + case ESHRASS: + which = 0; + if (left->type == IROLinearOp2Arg) { + if (left->nodetype == ComplementaryOp[nd->nodetype] || left->nodetype == AssignmentOp[ComplementaryOp[nd->nodetype]]) { + if (IRO_IsIntConstant(right) && IRO_ExprsSameSemantically(right, left->u.diadic.right)) + which = 2; + } + } + + if (which == 2) { + val = right->u.node->data.intval; + if (left->nodetype == ESHR || left->nodetype == ESHRASS) { + ReplaceExprWithLeftChild(left); + nd->nodetype = (nd->nodetype == ESHL) ? EAND : EANDASS; + right->u.node->data.intval = CInt64_Shl(cint64_negone, val); + changed = 1; + } else if (IRO_IsUnsignedType(nd->rtype)) { + ReplaceExprWithLeftChild(left); + nd->nodetype = (nd->nodetype == ESHR) ? EAND : EANDASS; + if (nd->rtype->size < 8) { + CInt64_SetLong(&size, 64 - 8 * nd->rtype->size); + val = CInt64_Add(val, size); + } + right->u.node->data.intval = CInt64_ShrU(cint64_negone, val); + changed = 1; + } + } + break; + } + } + + if (changed) { + DoTransformations(nd); + DoTransformations11(nd); + DoTransformations12(nd); + DoTransformations13(nd); + DoTransformations21(nd); + DoTransformations22(nd); + DoTransformations23(nd); + } + } +} + +static void DoTransformations24(IROLinear *nd) { + IROLinear *left; + IROLinear *right; + UInt8 changed; + + if (nd->type == IROLinearOp2Arg) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype)) + return; + + if (left->type == IROLinearOp2Arg && right->type == IROLinearOp2Arg && !IRO_HasSideEffect(nd)) { + changed = 0; + + if (IRO_ExprsSameSemantically(left->u.diadic.left, right->u.diadic.left)) { + if (left->nodetype == right->nodetype) { + switch (left->nodetype) { + case EADD: + if (nd->nodetype == ComplementaryOp[left->nodetype]) { + ReplaceExprWithRightChild(left); + ReplaceExprWithRightChild(right); + changed = 1; + } + break; + case ESUB: + if (nd->nodetype == ESUB || nd->nodetype == ESUBV) { + ReplaceExprWithRightChild(left); + ReplaceExprWithRightChild(right); + IRO_SwitchChildren(nd); + changed = 1; + } + break; + case EMUL: + switch (nd->nodetype) { + case EADD: + case ESUB: + PickCommonsubAtLeftLeft(nd); + changed = 3; + break; + } + break; + case EAND: + if (nd->nodetype == EXOR) { + PickCommonsubAtLeftLeft(nd); + changed = 3; + break; + } + case EOR: + if (nd->nodetype == left->nodetype) { + ReplaceExprWithRightChild(left); + changed = 1; + } else if (nd->nodetype == ComplementaryOp[left->nodetype]) { + PickCommonsubAtLeftLeft(nd); + changed = 3; + } + break; + } + } else if (left->nodetype == ComplementaryOp[right->nodetype]) { + switch (nd->nodetype) { + case ESUB: + case ESUBV: + switch (left->nodetype) { + case EADD: + nd->nodetype = ComplementaryOp[nd->nodetype]; + ReplaceExprWithRightChild(left); + ReplaceExprWithRightChild(right); + changed = 1; + break; + case ESUB: + ReplaceExprWithMonaminRight(left); + ReplaceExprWithRightChild(right); + changed = 1; + break; + } + break; + + case EAND: + case EOR: + if (left->nodetype == nd->nodetype) + ReplaceExprWithLeftChild(nd); + else if (right->nodetype == nd->nodetype) + ReplaceExprWithRightChild(nd); + break; + } + } + } else if (IRO_ExprsSameSemantically(left->u.diadic.right, right->u.diadic.left)) { + if (left->nodetype == right->nodetype) { + switch (left->nodetype) { + case EADD: + if (nd->nodetype == ComplementaryOp[left->nodetype]) { + ReplaceExprWithLeftChild(left); + ReplaceExprWithRightChild(right); + changed = 1; + } + break; + case EMUL: + switch (nd->nodetype) { + case EADD: + case ESUB: + PickCommonsubAtRightLeft(nd); + changed = 3; + break; + } + break; + case EAND: + if (nd->nodetype == EXOR) { + PickCommonsubAtRightLeft(nd); + changed = 3; + break; + } + case EOR: + if (nd->nodetype == left->nodetype) { + ReplaceExprWithLeftChild(left); + changed = 1; + } else if (nd->nodetype == ComplementaryOp[left->nodetype]) { + PickCommonsubAtRightLeft(nd); + changed = 3; + } + break; + } + } else if (left->nodetype == ComplementaryOp[right->nodetype]) { + switch (nd->nodetype) { + case ESUB: + case ESUBV: + if (left->nodetype == EADD) { + nd->nodetype = ComplementaryOp[nd->nodetype]; + ReplaceExprWithLeftChild(left); + ReplaceExprWithRightChild(right); + changed = 1; + } + break; + + case EADD: + case EADDV: + if (left->nodetype == ESUB) { + ReplaceExprWithLeftChild(left); + ReplaceExprWithRightChild(right); + changed = 1; + } + break; + + case EAND: + case EOR: + if (left->nodetype == nd->nodetype) + ReplaceExprWithLeftChild(nd); + else if (right->nodetype == nd->nodetype) + ReplaceExprWithRightChild(nd); + break; + } + } + } else if (IRO_ExprsSameSemantically(left->u.diadic.left, right->u.diadic.right)) { + if (left->nodetype == right->nodetype) { + switch (left->nodetype) { + case EADD: + if (nd->nodetype == ComplementaryOp[left->nodetype]) { + ReplaceExprWithRightChild(left); + ReplaceExprWithLeftChild(right); + changed = 1; + } + break; + case ESUB: + switch (nd->nodetype) { + case EADDV: + case EADD: + nd->nodetype = ComplementaryOp[nd->nodetype]; + ReplaceExprWithRightChild(left); + ReplaceExprWithLeftChild(right); + IRO_SwitchChildren(nd); + changed = 1; + break; + } + break; + case EMUL: + switch (nd->nodetype) { + case EADD: + case ESUB: + PickCommonsubAtLeftRight(nd); + changed = 2; + break; + } + break; + case EAND: + if (nd->nodetype == EXOR) { + PickCommonsubAtLeftRight(nd); + changed = 2; + break; + } + case EOR: + if (nd->nodetype == left->nodetype) { + ReplaceExprWithRightChild(left); + changed = 1; + } else if (nd->nodetype == ComplementaryOp[left->nodetype]) { + PickCommonsubAtLeftRight(nd); + changed = 2; + } + break; + } + } else if (left->nodetype == ComplementaryOp[right->nodetype]) { + switch (nd->nodetype) { + case EADD: + case EADDV: + if (left->nodetype == EADD) { + ReplaceExprWithRightChild(left); + ReplaceExprWithLeftChild(right); + changed = 1; + } + break; + + case ESUB: + case ESUBV: + if (left->nodetype == ESUB) { + ReplaceExprWithMonaminRight(left); + ReplaceExprWithRightChild(right); + changed = 1; + } + break; + + case EAND: + case EOR: + if (left->nodetype == nd->nodetype) + ReplaceExprWithLeftChild(nd); + else if (right->nodetype == nd->nodetype) + ReplaceExprWithRightChild(nd); + break; + } + } + } else if (IRO_ExprsSameSemantically(left->u.diadic.right, right->u.diadic.right)) { + if (left->nodetype == right->nodetype) { + switch (nd->nodetype) { + case ESUB: + switch (left->nodetype) { + case EADD: + case ESUB: + ReplaceExprWithLeftChild(left); + ReplaceExprWithLeftChild(right); + changed = 1; + } + case EADD: + switch (left->nodetype) { + case EMUL: + case ESHL: + PickCommonsubAtRightRight(nd); + changed = 2; + break; + } + break; + case EXOR: + switch (left->nodetype) { + case ESHL: + case ESHR: + case EAND: + PickCommonsubAtRightRight(nd); + changed = 2; + break; + } + break; + case EAND: + case EOR: + if (left->nodetype == nd->nodetype) { + ReplaceExprWithLeftChild(right); + changed = 1; + } else if ( + left->nodetype == ComplementaryOp[nd->nodetype] || + left->nodetype == ESHR || + left->nodetype == ESHL + ) + { + PickCommonsubAtRightRight(nd); + changed = 2; + } + break; + } + } else if (left->nodetype == ComplementaryOp[right->nodetype]) { + switch (nd->nodetype) { + case EADD: + case EADDV: + switch (left->nodetype) { + case EADD: + case ESUB: + ReplaceExprWithLeftChild(left); + ReplaceExprWithLeftChild(right); + changed = 1; + break; + } + break; + + case EAND: + case EOR: + if (left->nodetype == nd->nodetype) + ReplaceExprWithLeftChild(nd); + else if (right->nodetype == nd->nodetype) + ReplaceExprWithRightChild(nd); + break; + } + } + } + + if (changed) { + DoDiadic(nd); + if (changed == 2) + DoDiadic(nd->u.diadic.left); + else if (changed == 3) + DoDiadic(nd->u.diadic.right); + IRO_Dump("remove common op at: %d\n", nd->index); + } + } + } +} + +static void DoTransformations25(IROLinear *nd) { + int changed = 0; + IROLinear *left; + IROLinear *right; + + if (nd->type == IROLinearOp2Arg) { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + + if ( + (left->type == IROLinearOp2Arg && (IS_TYPE_FLOAT(left->u.diadic.left->rtype) || IS_TYPE_FLOAT(left->u.diadic.right->rtype))) || + (right->type == IROLinearOp2Arg && (IS_TYPE_FLOAT(right->u.diadic.left->rtype) || IS_TYPE_FLOAT(right->u.diadic.right->rtype))) + ) + return; + + switch (left->nodetype) { + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + switch (nd->nodetype) { + case EEQU: + if (IRO_IsConstantOne(right)) { + ReplaceExprWithLeftChild(nd); + changed = 1; + } else if (IRO_IsConstantZero(right)) { + left->nodetype = ComplementaryOpLogical[left->nodetype]; + ReplaceExprWithLeftChild(nd); + changed = 1; + } + break; + case ENOTEQU: + if (IRO_IsConstantOne(right)) { + left->nodetype = ComplementaryOpLogical[left->nodetype]; + ReplaceExprWithLeftChild(nd); + changed = 1; + } else if (IRO_IsConstantZero(right)) { + ReplaceExprWithLeftChild(nd); + changed = 1; + } + break; + } + break; + case ELAND: + case ELOR: + switch (nd->nodetype) { + case EEQU: + if (IRO_IsConstantOne(right)) { + ReplaceExprWithLeftChild(nd); + changed = 1; + } + break; + case ENOTEQU: + if (IRO_IsConstantZero(right)) { + ReplaceExprWithLeftChild(nd); + changed = 1; + } + break; + } + break; + } + + if (!changed) { + switch (right->nodetype) { + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + switch (nd->nodetype) { + case EEQU: + if (IRO_IsConstantOne(left)) { + ReplaceExprWithRightChild(nd); + } else if (IRO_IsConstantZero(left)) { + right->nodetype = ComplementaryOpLogical[right->nodetype]; + ReplaceExprWithRightChild(nd); + } + break; + case ENOTEQU: + if (IRO_IsConstantOne(left)) { + right->nodetype = ComplementaryOpLogical[right->nodetype]; + ReplaceExprWithRightChild(nd); + } else if (IRO_IsConstantZero(left)) { + ReplaceExprWithRightChild(nd); + } + break; + } + break; + case ELAND: + case ELOR: + switch (nd->nodetype) { + case EEQU: + if (IRO_IsConstantOne(left)) { + ReplaceExprWithRightChild(nd); + } + break; + case ENOTEQU: + if (IRO_IsConstantZero(left)) { + ReplaceExprWithRightChild(nd); + } + break; + } + break; + } + } + } +} + +static Boolean isOrderingOperator(ENodeType op) { + switch (op) { + case ELAND: + case ELOR: + case ECOMMA: + case ECOND: + case ECONDASS: + return 1; + default: + return 0; + } +} + +static void RemoveUnreffed(IROLinear *nd) { + if (!(nd->flags & IROLF_Reffed)) { + switch (nd->type) { + case IROLinearOperand: + IRO_NopNonSideEffects(nd, 0); + break; + case IROLinearOp1Arg: + case IROLinearOp2Arg: + case IROLinearOp3Arg: + case IROLinearFunccall: + if (!isOrderingOperator(nd->nodetype)) + IRO_NopNonSideEffects(nd, 0); + break; + } + } +} + +static void RemoveRedundantMonadicOp(IROLinear *nd) { + IROLinear *nd2; + IROLinear *nd3; + + if (nd->type == IROLinearOp1Arg && (nd2 = IRO_LocateFather(nd)) && nd2->nodetype == nd->nodetype) { + switch (nd->nodetype) { + case ELOGNOT: + if ((nd3 = IRO_LocateFather(nd2))) { + if ( + nd3->rtype && + TYPE_INTEGRAL(nd3->rtype)->integral == IT_BOOL && + nd->u.monadic->rtype && + TYPE_INTEGRAL(nd->u.monadic->rtype)->integral == IT_BOOL + ) + goto remove; + + if (nd3->type == IROLinearIf) + goto remove; + if (nd3->type == IROLinearIfNot) + goto remove; + if (nd3->type == IROLinearOp3Arg && nd == nd3->u.args3.a) + goto remove; + + switch (nd3->nodetype) { + case ELOGNOT: + case ELAND: + case ELOR: + goto remove; + } + } + + if (nd->u.monadic->type == IROLinearOp1Arg || nd->u.monadic->type == IROLinearOp2Arg) { + switch (nd->u.monadic->nodetype) { + case ELOGNOT: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case ELAND: + case ELOR: + goto remove; + } + } + break; + + case EMONMIN: + case EBINNOT: + remove: + IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd2, nd->u.monadic); + nd2->type = IROLinearNop; + nd->type = IROLinearNop; + break; + + case ETYPCON: + if (TYPE_INTEGRAL(nd->rtype)->integral == IT_FLOAT) { + switch (TYPE_INTEGRAL(nd2->rtype)->integral) { + case IT_DOUBLE: + case IT_LONGDOUBLE: + switch (TYPE_INTEGRAL(nd->u.monadic->rtype)->integral) { + case IT_BOOL: + case IT_CHAR: + case IT_SCHAR: + case IT_UCHAR: + case IT_SHORT: + case IT_USHORT: + nd->type = IROLinearNop; + nd2->u.monadic = nd->u.monadic; + break; + } + break; + } + } + break; + } + } +} + +static void ReverseOpForMonmin(IROLinear *nd) { + IROLinear *father; + + if ( + nd->type == IROLinearOp1Arg && + nd->nodetype == EMONMIN && + (father = IRO_LocateFather(nd)) && + father->type == IROLinearOp2Arg && + father->u.diadic.right == nd + ) + { + switch (father->nodetype) { + case EADDV: + case ESUBV: + case EADD: + case ESUB: + case EADDASS: + case ESUBASS: + father->nodetype = ComplementaryOp[father->nodetype]; + nd->type = IROLinearNop; + father->u.diadic.right = nd->u.monadic; + break; + } + } +} + +static void DoDiadic(IROLinear *nd) { + RemoveUnreffed(nd); + DoTransformations(nd); + DoTransformations11(nd); + DoTransformations12(nd); + DoTransformations13(nd); + DoTransformations21(nd); + DoTransformations22(nd); + DoTransformations23(nd); + DoTransformations24(nd); + DoTransformations25(nd); +} + +void IRO_DoTransformations(void) { + IROLinear *nd; + + for (nd = IRO_FirstLinear; nd; nd = nd->next) { + switch (nd->type) { + case IROLinearOp2Arg: + DoDiadic(nd); + break; + case IROLinearOp1Arg: + RemoveUnreffed(nd); + RemoveRedundantMonadicOp(nd); + ReverseOpForMonmin(nd); + break; + case IROLinearOperand: + RemoveUnreffed(nd); + break; + } + } + + IRO_CheckForUserBreak(); +} + +static Boolean ReconcileAssignments(IROLinear *nd1, IROLinear *nd2, IROList *list) { + IROLinear *copy; + Boolean result = 0; + int argCount; + int i; + IROLinear *tmp; + + if ( + (nd2->type == IROLinearOp1Arg && nd2->nodetype == ETYPCON) && + !(nd1->type == IROLinearOp1Arg && nd1->nodetype == ETYPCON) && + ReconcileAssignments(nd1, nd2->u.monadic, list) + ) + { + result = 1; + } + + if ( + (nd1->type == IROLinearOp1Arg && nd1->nodetype == ETYPCON) && + !(nd2->type == IROLinearOp1Arg && nd2->nodetype == ETYPCON) && + ReconcileAssignments(nd1->u.monadic, nd2, list) + ) + { + copy = IRO_NewLinear(IROLinearOp1Arg); + *copy = *nd2; + copy->index = IRO_NumLinear++; + copy->type = IROLinearOp1Arg; + copy->nodetype = ETYPCON; + copy->rtype = nd1->rtype; + copy->next = NULL; + copy->u.monadic = list->tail; + IRO_AddToList(copy, list); + result = 1; + } + + if (nd1->type == nd2->type && nd1->nodetype == nd2->nodetype) { + copy = IRO_NewLinear(IROLinearNop); + *copy = *nd2; + copy->index = IRO_NumLinear++; + copy->rtype = nd1->rtype; + copy->next = NULL; + switch (nd1->type) { + case IROLinearOperand: + if (nd1->u.node->type == nd2->u.node->type) { + if (!(nd1->u.node->type == EOBJREF && nd1->u.node->data.objref != nd2->u.node->data.objref)) + result = 1; + } + break; + + case IROLinearOp1Arg: + if (ReconcileAssignments(nd1->u.monadic, nd2->u.monadic, list)) { + copy->u.monadic = list->tail; + result = 1; + } + break; + + case IROLinearOp2Arg: + tmp = list->tail; + if (ReconcileAssignments(nd1->u.diadic.left, nd2->u.diadic.left, list)) { + copy->u.diadic.left = list->tail; + if (ReconcileAssignments(nd1->u.diadic.right, nd2->u.diadic.right, list)) { + copy->u.diadic.right = list->tail; + result = 1; + } + } + + if (!result && !IRO_HasSideEffect(nd1) && !IRO_HasSideEffect(nd2)) { + if (nd1->nodetype == EMUL || nd1->nodetype == EADD || nd1->nodetype == EAND || nd1->nodetype == EXOR || nd1->nodetype == EOR) { + list->tail = tmp; + if (ReconcileAssignments(nd1->u.diadic.left, nd2->u.diadic.right, list)) { + copy->u.diadic.right = list->tail; + if (ReconcileAssignments(nd1->u.diadic.right, nd2->u.diadic.left, list)) { + copy->u.diadic.left = list->tail; + result = 1; + } + } + } + } + break; + + case IROLinearOp3Arg: + if (ReconcileAssignments(nd1->u.args3.c, nd2->u.args3.c, list)) { + copy->u.args3.c = list->tail; + if (ReconcileAssignments(nd1->u.args3.b, nd2->u.args3.b, list)) { + copy->u.args3.b = list->tail; + if (ReconcileAssignments(nd1->u.args3.a, nd2->u.args3.a, list)) { + copy->u.args3.a = list->tail; + result = 1; + } + } + } + break; + + case IROLinearFunccall: + argCount = nd1->u.funccall.argCount; + if (argCount == nd2->u.funccall.argCount) { + result = 1; + copy->u.funccall.args = oalloc(sizeof(IROLinear *) * argCount); + for (i = argCount - 1; i >= 0; i--) { + if (!ReconcileAssignments(nd1->u.funccall.args[i], nd2->u.funccall.args[i], list)) { + result = 0; + break; + } + copy->u.funccall.args[i] = list->tail; + } + + if (result) { + if (!ReconcileAssignments(nd1->u.funccall.linear8, nd2->u.funccall.linear8, list)) { + result = 0; + break; + } + copy->u.funccall.linear8 = list->tail; + } + } + break; + } + + if (result) + IRO_AddToList(copy, list); + } + + return result; +} + +static IROLinear *FrontendTransformSelfAssignmentToAssignment(IROLinear *nd) { + Statement *stmt; + IROList list; + IROLinearIRSave save; + + IRO_SaveLinearIR(&save); + + IRO_InitList(&list); + IRO_DuplicateExpr(nd, &list); + + stmt = IRO_Delinearize(NULL, list.head); + CError_ASSERT(3550, stmt); + CError_ASSERT(3552, stmt->expr); + stmt->expr = CIRTrans_TransformOpAss(stmt->expr); + CError_ASSERT(3557, stmt->expr); + + if (DoLinearize) + IRO_PreLinearize(stmt); + IRO_Linearize(stmt); + + IRO_InitList(&list); + list.head = IRO_FirstLinear; + list.tail = IRO_LastLinear; + + IRO_RestoreLinearIR(&save); + + for (nd = list.head; nd; nd = nd->next) { + if (!(nd->flags & IROLF_Reffed) && IRO_IsAssignment(nd)) + break; + } + + return nd; +} + +static Type *PromotedIntegralType(Type *type) { + CError_ASSERT(3586, IS_TYPE_ENUM(type) || IS_TYPE_INT(type)); + + if (IS_TYPE_ENUM(type)) + type = TYPE_ENUM(type)->enumtype; + + if (TYPE_INTEGRAL(type)->integral < IT_INT) { + if (IRO_IsUnsignedType(type)) + return TYPE(&stunsignedint); + else + return TYPE(&stsignedint); + } else { + return type; + } +} + +static Boolean TransformMonadicSelfAssignmentToDiadicSelfAssignment(IROLinear *nd) { + ENodeType t; + ENodeType newtype; + IROLinear *incExpr; + IROLinear *varExpr; + + t = nd->nodetype; + + if (IRO_IsAssignment(nd) && IRO_IsModifyOp[t]) { + incExpr = NULL; + varExpr = NULL; + newtype = MAXEXPR; + + if ( + nd->type == IROLinearOp1Arg && + (t == EPOSTINC || t == EPOSTDEC || t == EPREINC || t == EPREDEC) && + (!(nd->flags & IROLF_Reffed) || t == EPREINC || t == EPREDEC) + ) + { + Type *type = nd->rtype; + TypeType typetype = type->type; + varExpr = nd->u.monadic; + if (typetype == TYPEINT || typetype == TYPEENUM) { + incExpr = IRO_NewIntConst(cint64_one, PromotedIntegralType(type)); + } else if (typetype == TYPEPOINTER || typetype == TYPEARRAY || typetype == TYPEMEMBERPOINTER) { + Type *inner = NULL; + CInt64 val = cint64_zero; + + if (typetype == TYPEPOINTER || typetype == TYPEARRAY) + inner = TPTR_TARGET(type); + else if (typetype == TYPEMEMBERPOINTER) + inner = TYPE_MEMBER_POINTER(type)->ty1; + + if (inner) + CInt64_SetLong(&val, inner->size); + + if (!CInt64_IsZero(&val)) { + incExpr = IRO_NewIntConst(val, TYPE(&stsignedlong)); + } else { + return 0; + } + } else if (typetype == TYPEFLOAT) { + Float fval; + fval = CMach_CalcFloatConvertFromInt(type, cint64_one); + incExpr = IRO_NewFloatConst(fval, nd->rtype); + } else { + return 0; + } + + if (t == EPOSTINC || t == EPREINC) + newtype = EADDASS; + else + newtype = ESUBASS; + } + + if ( + varExpr && + incExpr && + newtype != MAXEXPR && + varExpr->u.diadic.left && + varExpr->u.diadic.left->type == IROLinearOperand && + varExpr->u.diadic.left->u.node && + varExpr->u.diadic.left->u.node->type == EOBJREF && + !IRO_HasSideEffect(varExpr) + ) + { + incExpr->flags |= IROLF_Reffed; + nd->nodetype = newtype; + nd->u.diadic.right = incExpr; + nd->type = IROLinearOp2Arg; + IRO_Paste(incExpr, incExpr, nd); + return 1; + } + } + + return 0; +} + +Boolean IRO_TransformSelfAssignmentToAssignment(IROLinear *nd) { + ENodeType nonAssOp; + IROLinear *left; + IROLinear *right; + ENodeType nodetype; + IROLinear *nonAss; + IROLinear *dupLeft; + IROLinear *last; + IROList list1; + IROList list2; + + nodetype = nd->nodetype; + if ( + IRO_IsAssignment(nd) && + IRO_IsModifyOp[nodetype] && + nd->type == IROLinearOp1Arg && + TransformMonadicSelfAssignmentToDiadicSelfAssignment(nd) + ) + nodetype = nd->nodetype; + + if ( + IRO_IsAssignment(nd) && + IRO_IsModifyOp[nodetype] && + nd->type == IROLinearOp2Arg && + IRO_NonAssignmentOp[nodetype] != MAXEXPR + ) + { + left = nd->u.diadic.left; + right = nd->u.diadic.right; + nonAssOp = IRO_NonAssignmentOp[nodetype]; + if ( + left && + right && + nonAssOp != MAXEXPR && + left->u.monadic && + left->u.monadic->type == IROLinearOperand && + left->u.monadic->u.node && + left->u.monadic->u.node->type == EOBJREF && + !IRO_HasSideEffect(left) + ) + { + IRO_InitList(&list1); + dupLeft = IRO_DuplicateExpr(left, &list1); + + if (left->rtype != right->rtype) { + IROLinear *tmp = IRO_NewLinear(IROLinearOp1Arg); + tmp->nodetype = ETYPCON; + tmp->flags |= IROLF_Reffed; + tmp->rtype = right->rtype; + tmp->index = ++IRO_NumLinear; + tmp->u.monadic = dupLeft; + IRO_AddToList(tmp, &list1); + dupLeft = tmp; + } + + nonAss = IRO_NewLinear(IROLinearOp2Arg); + nonAss->nodetype = nonAssOp; + nonAss->flags |= IROLF_Reffed; + nonAss->rtype = dupLeft->rtype; + nonAss->index = ++IRO_NumLinear; + nonAss->u.diadic.left = dupLeft; + nonAss->u.diadic.right = right; + IRO_AddToList(nonAss, &list1); + + if (left->rtype != right->rtype) { + IROLinear *tmp = IRO_NewLinear(IROLinearOp1Arg); + tmp->nodetype = ETYPCON; + tmp->flags |= IROLF_Reffed; + tmp->rtype = left->rtype; + tmp->index = ++IRO_NumLinear; + tmp->u.monadic = nonAss; + IRO_AddToList(tmp, &list1); + nonAss = tmp; + } + + IRO_InitList(&list2); + last = FrontendTransformSelfAssignmentToAssignment(nd); + if ( + last && + last->type == IROLinearOp2Arg && + ReconcileAssignments(last->u.diadic.right, nonAss, &list2) + ) + { + IRO_NopOut(nd->u.diadic.right); + nd->nodetype = EASS; + nd->u.diadic.right = list2.tail; + nd->type = IROLinearOp2Arg; + IRO_Paste(list2.head, list2.tail, nd); + return 1; + } + } + } + + return 0; +} + +static void AddAddend(ENode *expr) { + if (expr->type == EADD) { + AddAddend(expr->data.diadic.left); + AddAddend(expr->data.diadic.right); + } else { + ENodeList *list = oalloc(sizeof(ENodeList)); + list->node = expr; + list->next = NULL; + + if (FirstAddend) + LastAddend->next = list; + else + FirstAddend = list; + LastAddend = list; + } +} + +static ENode *CombineConstants(ENode *expr) { + ENode *addend; + ENodeList *el; + ENode *result; + ENode *var; + Type *type; + ENode *tmp; + ENodeList *prev; + CInt64 val; + + FirstAddend = LastAddend = NULL; + AddAddend(expr->data.diadic.left); + AddAddend(expr->data.diadic.right); + + // these variable names are courtesy of the resource fork in abort_exit.c + el = FirstAddend; + prev = NULL; + var = NULL; + while (el) { + addend = el->node; + if (addend->type == EOBJREF) { + var = addend; + if (prev) + prev->next = el->next; + else + FirstAddend = el->next; + break; + } + prev = el; + el = el->next; + } + + if (!var) { + el = FirstAddend; + prev = NULL; + while (el) { + addend = el->node; + if (addend->type == EINDIRECT) { + var = addend; + if (prev) + prev->next = el->next; + else + FirstAddend = el->next; + break; + } + prev = el; + el = el->next; + } + } + + prev = NULL; + CInt64_SetLong(&val, 0); + type = NULL; + + for (el = FirstAddend; el; el = el->next) { + addend = el->node; + if (addend->type == EINTCONST && addend->rtype) { + if (!type || type->size < addend->rtype->size) + type = addend->rtype; + val = CInt64_Add(val, addend->data.intval); + if (prev) + prev->next = el->next; + else + FirstAddend = el->next; + } else if (addend->type == EMUL && addend->data.diadic.right->type == EINTCONST && addend->rtype) { + if (!type || type->size < addend->rtype->size) + type = addend->rtype; + + tmp = addend->data.diadic.left; + if (tmp->type == EADD && tmp->data.diadic.right->type == EINTCONST) { + val = CInt64_Add(val, CInt64_MulU(tmp->data.diadic.right->data.intval, addend->data.diadic.right->data.intval)); + addend->data.diadic.left = tmp->data.diadic.left; + } + prev = el; + } else { + prev = el; + } + } + + result = NULL; + if (var) { + result = var; + if (!CInt64_IsZero(&val)) { + result = IRO_NewENode(EADD); + result->data.diadic.left = var; + result->data.diadic.right = IRO_NewENode(EINTCONST); + result->data.diadic.right->data.intval = val; + result->data.diadic.right->rtype = type; + result->rtype = var->rtype; + result->cost = 1; + CInt64_SetLong(&val, 0); + } + } + + for (el = FirstAddend; el; el = el->next) { + addend = el->node; + if (result) { + tmp = IRO_NewENode(EADD); + tmp->data.diadic.left = result; + tmp->data.diadic.right = addend; + tmp->cost = result->cost + 1; + tmp->rtype = result->rtype; + result = tmp; + } else { + result = addend; + } + } + + if (!CInt64_IsZero(&val)) { + tmp = IRO_NewENode(EADD); + tmp->data.diadic.left = result; + tmp->data.diadic.right = IRO_NewENode(EINTCONST); + tmp->data.diadic.right->data.intval = val; + tmp->data.diadic.right->rtype = type; + tmp->cost = result->cost + 1; + tmp->rtype = result->rtype; + result = tmp; + } + + return result; +} + +static ENode *TransformExprNode(ENode *expr) { + ENode *left; + ENode *right; + + switch (expr->type) { + case EINDIRECT: + if (ENODE_IS(expr->data.monadic, EADD)) + expr->data.monadic = CombineConstants(expr->data.monadic); + break; + + case EMUL: + case EADD: + case EAND: + case EXOR: + case EOR: + if ( + IS_TYPE_INT(expr->rtype) && + !ENODE_IS(right = expr->data.diadic.right, EINTCONST) && + ENODE_IS(left = expr->data.diadic.left, EINTCONST) + ) + { + expr->data.diadic.left = right; + expr->data.diadic.right = left; + } + break; + + case EEQU: + case ENOTEQU: + if ( + IS_TYPE_INT(expr->rtype) && + !ENODE_IS(left = expr->data.diadic.right, EINTCONST) && + ENODE_IS(right = expr->data.diadic.left, EINTCONST) + ) + { + expr->data.diadic.left = left; + expr->data.diadic.right = right; + } + + if ( + ENODE_IS(expr->data.diadic.right, EINTCONST) && + ENODE_IS(left = expr->data.diadic.left, EBINNOT) + ) + { + expr->data.diadic.left = left->data.monadic; + left->data.monadic = expr->data.diadic.right; + expr->data.diadic.right = left; + } + + break; + } + + return expr; +} + +static ENode *TransformExprTree(ENode *expr) { + ENodeList *list; + + switch (expr->type) { + ENODE_CASE_MONADIC: + expr->data.monadic = TransformExprTree(expr->data.monadic); + break; + + ENODE_CASE_DIADIC_ALL: + expr->data.diadic.left = TransformExprTree(expr->data.diadic.left); + expr->data.diadic.right = TransformExprTree(expr->data.diadic.right); + break; + + case EFUNCCALL: + case EFUNCCALLP: + TransformExprTree(expr->data.funccall.funcref); + for (list = expr->data.funccall.args; list; list = list->next) + TransformExprTree(list->node); + break; + + case ECOND: + TransformExprTree(expr->data.cond.cond); + TransformExprTree(expr->data.cond.expr1); + TransformExprTree(expr->data.cond.expr2); + break; + + case ENULLCHECK: + TransformExprTree(expr->data.nullcheck.nullcheckexpr); + TransformExprTree(expr->data.nullcheck.condexpr); + break; + } + + return TransformExprNode(expr); +} + +static void FoldConstantsinAssociativeExprs(ENode *expr) { + short nodetype1; + short nodetype2; + short nodetype3; + Boolean changed; + short op; + CInt64 val1; + CInt64 val2; + CInt64 tmpval; + + if ( + ( + expr->type == EADD || + expr->type == EMUL || + expr->type == EAND || + expr->type == EXOR || + expr->type == EOR || + expr->type == ESHL || + expr->type == ESHR + ) && + IS_TYPE_INT(expr->rtype) && + expr->data.diadic.right->type == EINTCONST + ) + { + do { + changed = 0; + + if ( + expr->data.diadic.left->type == expr->type && + expr->data.diadic.left->data.diadic.right->type == EINTCONST + ) + { + val1 = expr->data.diadic.right->data.intval; + val2 = expr->data.diadic.left->data.diadic.right->data.intval; + switch (expr->type) { + case EADD: + case ESHL: + op = '+'; + break; + case ESHR: + op = '+'; + if (!IRO_IsUnsignedType(expr->rtype)) { + CInt64_SetLong(&tmpval, expr->rtype->size * 8); + if (CInt64_GreaterEqualU(val1, tmpval) || CInt64_GreaterEqualU(val2, tmpval)) + return; + + if (CInt64_GreaterEqualU(CMach_CalcIntDiadic(expr->rtype, val1, '+', val2), tmpval)) { + val1 = CInt64_Sub(tmpval, cint64_one); + val2 = cint64_zero; + } + } + break; + case EMUL: + op = '*'; + break; + case EAND: + op = '&'; + break; + case EOR: + op = '|'; + break; + case EXOR: + op = '^'; + break; + default: + return; + } + + expr->data.diadic.right->data.intval = CMach_CalcIntDiadic(expr->rtype, val1, op, val2); + expr->data.diadic.left = expr->data.diadic.left->data.diadic.left; + changed = 1; + } else if ( + ((nodetype1 = expr->type) == EAND || nodetype1 == EOR) && + ((nodetype2 = expr->data.diadic.left->type) == EAND || nodetype2 == EOR) && + ((nodetype3 = expr->data.diadic.left->data.diadic.left->type) == EAND || nodetype3 == EOR) && + expr->data.diadic.left->data.diadic.left->data.diadic.right->type == EINTCONST + ) + { + val1 = expr->data.diadic.right->data.intval; + if (CInt64_Equal(val1, expr->data.diadic.left->data.diadic.left->data.diadic.right->data.intval)) { + if (nodetype1 == nodetype3) { + expr->data.diadic.left->data.diadic.left = expr->data.diadic.left->data.diadic.left->data.diadic.left; + changed = 1; + } else if (nodetype2 == nodetype3) { + *expr = *expr->data.diadic.right; + changed = 1; + } else { + expr->data.diadic.left = expr->data.diadic.left->data.diadic.right; + changed = 1; + } + } + } + } while (changed); + } +} + +static void TransformExprTree1(ENode *expr) { + ENodeList *list; + + switch (expr->type) { + ENODE_CASE_MONADIC: + TransformExprTree1(expr->data.monadic); + break; + + ENODE_CASE_DIADIC_ALL: + TransformExprTree1(expr->data.diadic.left); + TransformExprTree1(expr->data.diadic.right); + break; + + case EFUNCCALL: + case EFUNCCALLP: + TransformExprTree1(expr->data.funccall.funcref); + for (list = expr->data.funccall.args; list; list = list->next) + TransformExprTree1(list->node); + break; + + case ECOND: + TransformExprTree1(expr->data.cond.cond); + TransformExprTree1(expr->data.cond.expr1); + TransformExprTree1(expr->data.cond.expr2); + break; + + case ENULLCHECK: + TransformExprTree1(expr->data.nullcheck.nullcheckexpr); + TransformExprTree1(expr->data.nullcheck.condexpr); + break; + } + + FoldConstantsinAssociativeExprs(expr); +} + +static int RemoveRedundantBitOperations(ENode *expr) { + Boolean a; + Boolean b; + + if (expr->type == ExprType) { + a = RemoveRedundantBitOperations(expr->data.diadic.left); + b = RemoveRedundantBitOperations(expr->data.diadic.right); + return a & b; + } + + if (expr->type == EINDIRECT) { + if (expr->data.monadic->type == EOBJREF) { + if (!OperandObject) { + OperandObject = expr->data.monadic->data.objref; + IndirectRef = expr; + return 1; + } else { + return expr->data.monadic->data.objref == OperandObject; + } + } else { + return 0; + } + } + + if (expr->type == EINTCONST) { + if (FirstTime) { + OperandConst = expr->data.intval; + FirstTime = 0; + } else if (ExprType == EAND) { + OperandConst = CInt64_And(expr->data.intval, OperandConst); + } else if (ExprType == EOR) { + OperandConst = CInt64_Or(expr->data.intval, OperandConst); + } else if (ExprType == EXOR) { + OperandConst = CInt64_Xor(expr->data.intval, OperandConst); + } + return 1; + } + + return 0; +} + +static void TransformExprTree2(ENode *expr) { + ENodeList *list; + + switch (expr->type) { + ENODE_CASE_MONADIC: + TransformExprTree2(expr->data.monadic); + break; + + ENODE_CASE_DIADIC_ALL: + TransformExprTree2(expr->data.diadic.left); + TransformExprTree2(expr->data.diadic.right); + break; + + case EFUNCCALL: + case EFUNCCALLP: + TransformExprTree2(expr->data.funccall.funcref); + for (list = expr->data.funccall.args; list; list = list->next) + TransformExprTree2(list->node); + break; + + case ECOND: + TransformExprTree2(expr->data.cond.cond); + TransformExprTree2(expr->data.cond.expr1); + TransformExprTree2(expr->data.cond.expr2); + break; + + case ENULLCHECK: + TransformExprTree2(expr->data.nullcheck.nullcheckexpr); + TransformExprTree2(expr->data.nullcheck.condexpr); + break; + } + + if ( + ENODE_IS3(expr, EAND, EOR, EXOR) && + (expr->type == expr->data.diadic.left->type || expr->type == expr->data.diadic.right->type) + ) + { + OperandObject = NULL; + ExprType = expr->type; + FirstTime = 1; + IndirectRef = NULL; + + if (RemoveRedundantBitOperations(expr)) { + expr->data.diadic.left = IndirectRef; + expr->data.diadic.right->type = EINTCONST; + expr->data.diadic.right->data.intval = OperandConst; + } + } +} + +static void PullOutPostOps(Statement *stmt, ENode **pExpr) { + ENode *ind; + ENode *inner; + Statement *newStmt; + + switch ((*pExpr)->type) { + ENODE_CASE_MONADIC: + if ((*pExpr)->type != EFORCELOAD) + PullOutPostOps(stmt, &(*pExpr)->data.monadic); + + if (ENODE_IS2(*pExpr, EPOSTINC, EPOSTDEC)) { + inner = (*pExpr)->data.monadic; + if ( + ENODE_IS(inner, EINDIRECT) && + inner->rtype && + !CParser_IsVolatile(inner->rtype, ENODE_QUALS(inner)) && + ENODE_IS(inner->data.monadic, EOBJREF) && + !is_volatile_object(inner->data.monadic->data.objref) + ) + { + newStmt = lalloc(sizeof(Statement)); + memset(newStmt, 0, sizeof(Statement)); + newStmt->type = ST_EXPRESSION; + newStmt->expr = *pExpr; + newStmt->dobjstack = stmt->dobjstack; + newStmt->sourceoffset = stmt->sourceoffset; + newStmt->sourcefilepath = stmt->sourcefilepath; + newStmt->value = stmt->value; + newStmt->flags = stmt->flags; + newStmt->next = stmt->next; + stmt->next = newStmt; + + ind = IRO_NewENode(EINDIRECT); + *ind = *inner; + ind->data.monadic = IRO_NewENode(EOBJREF); + *ind->data.monadic = *inner->data.monadic; + *pExpr = ind; + } + } + break; + + ENODE_CASE_DIADIC_ALL: + if (ENODE_IS(*pExpr, ECOND)) + break; + if (ENODE_IS(*pExpr, ECOMMA)) + break; + if (ENODE_IS(*pExpr, ELOR)) + break; + if (ENODE_IS(*pExpr, ELAND)) + break; + if (ENODE_IS(*pExpr, ENULLCHECK)) + break; + PullOutPostOps(stmt, &(*pExpr)->data.diadic.left); + PullOutPostOps(stmt, &(*pExpr)->data.diadic.right); + break; + } +} + +void IRO_TransformTree(Statement *statements) { + Statement *stmt; + Statement *next; + + for (stmt = statements; stmt; stmt = next) { + next = stmt->next; + switch (stmt->type) { + case ST_EXPRESSION: + case ST_SWITCH: + case ST_IFGOTO: + case ST_IFNGOTO: + case ST_RETURN: + if (stmt->expr) { + stmt->expr = TransformExprTree(stmt->expr); + TransformExprTree2(stmt->expr); + TransformExprTree1(stmt->expr); + } + break; + } + } + + IRO_CheckForUserBreak(); +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroTransform.h b/compiler_and_linker/FrontEnd/Optimizer/IroTransform.h new file mode 100644 index 0000000..104657f --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroTransform.h @@ -0,0 +1,13 @@ +#ifndef COMPILER_IROTRANSFORM_H +#define COMPILER_IROTRANSFORM_H + +#include "IrOptimizer.h" + +extern void IRO_InitializeAssignmentOpArray(void); +extern void IRO_InitializeComplementaryOpArray(void); +extern void IRO_InitializeComplementaryOpLogicalArray(void); +extern void IRO_DoTransformations(void); +extern Boolean IRO_TransformSelfAssignmentToAssignment(IROLinear *nd); +extern void IRO_TransformTree(Statement *statements); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.c b/compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.c new file mode 100644 index 0000000..cf3f1bf --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.c @@ -0,0 +1,2305 @@ +#include "IroUnrollLoop.h" +#include "compiler/CError.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroUtil.h" +#include "compiler/LoopDetection.h" +#include "IroLoop.h" +#include "IroDump.h" +#include "IroVars.h" +#include "compiler/CFunc.h" +#include "compiler/CMachine.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct LoopList { + UInt8 flags; + BitVector *bv; + struct LoopList *next; + IRONode *fnode; + int xE; +} LoopList; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +// forward decls +static void IRO_FindLoops_Unroll(void); +static void LoopUnroll(int count, IRONode *fnode); +static int IsLoopUnrollable(IROLoop *loop); +static int IsDifferenceOfTermsConstant(IROAddrRecord *lowerRec, IROAddrRecord *upperRec, int isUnsigned, CInt64 *pval); +static IROLinear *BuildOrigIterationCount_DoWhile(IROList *list, IROLoop *loop); +static IROLinear *BuildPreAlignTemp(IROLoopInd *ind, UInt32 unrollFactor, IROList *list); +static IROLinear *BuildNewFinalvalue_DoWhile(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop); +static IROLinear *BuildUnrolledFinalvalue_DoWhile(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop); + +void IRO_LoopUnroller(void) { + VectorPhaseCalledFromUnroll = 1; + IRO_FindLoops_Unroll(); + IRO_CheckForUserBreak(); +} + +static void IRO_FindLoops_Unroll(void) { + IRONode *fnode; + IRONode *pred; + UInt16 i; + UInt16 flag; + LoopList *list; + LoopList *list2; + + fnode = IRO_FirstNode; + LoopList_First = NULL; + + while (fnode) { + flag = 0; + for (i = 0; i < fnode->numpred; i++) { + pred = IRO_NodeTable[fnode->pred[i]]; + if (Bv_IsBitSet(fnode->index, pred->dom)) { + if (!flag) { + Bv_AllocVector(&InLoop, IRO_NumNodes + 1); + Bv_Clear(InLoop); + Bv_SetBit(fnode->index, InLoop); + } + flag = 1; + Bv_SetBit(pred->index, InLoop); + if (pred != fnode) + AddPreds(pred); + } + } + + if (flag) { + if (!LoopList_First) { + list = oalloc(sizeof(LoopList)); + list->next = NULL; + } else { + list = oalloc(sizeof(LoopList)); + list->next = LoopList_First; + } + LoopList_First = list; + + Bv_AllocVector(&list->bv, IRO_NumNodes + 1); + list->flags |= 1; + Bv_Copy(InLoop, list->bv); + list->fnode = fnode; + list->xE = 0; + } + + fnode = fnode->nextnode; + } + + list = LoopList_First; + Bv_AllocVector(&LoopTemp, IRO_NumNodes + 1); + while (list) { + for (list2 = LoopList_First; list2; list2 = list2->next) { + if (list2 != list) { + IRO_Dump(" header = %d \n", list2->fnode->index); + IRO_Dump(" l1 bit vector=\n"); + IRO_DumpBits("", list2->bv); + IRO_Dump(" l bit vector=\n"); + IRO_DumpBits("", list->bv); + if (Bv_IsSubset(list->bv, list2->bv)) + list2->flags &= ~1; + } + } + list = list->next; + } + + for (list = LoopList_First; list; list = list->next) { + if (list->flags & 1) { + IRONode *listfnode; + Bv_Copy(list->bv, InLoop); + listfnode = list->fnode; + IRO_Dump("IRO_FindLoops_Unroll:Found loop with header %d\n", listfnode->index); + IRO_DumpBits("Loop includes: ", InLoop); + LoopUnroll(copts.unrollfactor, listfnode); + IRO_UpdateFlagsOnInts(); + } + } +} + +static int CheckConstant(CInt64 a, CInt64 b, CInt64 *result) { + CInt64 shl = cint64_zero; + CInt64 work = cint64_zero; + CInt64 and = cint64_zero; + CInt64 i; + + for (i = cint64_zero; CInt64_Less(i, a); i = CInt64_Add(i, cint64_one)) { + shl = CInt64_Shl(b, i); + and = CInt64_And(shl, work); + if (CInt64_NotEqual(and, cint64_zero)) + return 0; + work = CInt64_Or(shl, work); + } + + *result = work; + return 1; +} + +typedef struct LoopPattern { + IROLinear *nd0; + IROLinear *nd4; + Type *type; + IROLinear *ndC; + IROLinear *nd10; + CInt64 val14; + CInt64 val1C; +} LoopPattern; + +static void UnrollWhileLoopBody(IRONode *header, IRONode *fnode2, IRONode *fnode3, IROLoop *loop, LoopPattern *pattern, UInt32 unrollFactor) { + IRONode *scan; + int pass; + IROLinear *firstnode; + IROLinear *lastnd; + IROLinear *nd; + IROLinear *nd1; + IROLinear *nd2; + IROLinear *nd3; + IROLinear *nd4; + IROLinear *nd5; + IROLinear *nd6; + IROLinear *nd8; + IROLinear *nd7; + ENode *expr; + IROList list; + CInt64 zero; + CInt64 shiftval; + + CInt64_SetLong(&zero, 0); + + pass = 0; + + do { + firstnode = NULL; + for (scan = fnode3; scan && scan != header; scan = scan->nextnode) { + IRO_InitList(&list); + lastnd = scan->last; + nd = scan->first; + while (1) { + if (nd->stmt) + nd->stmt->flags |= StmtFlag_10; + + if ( + (nd->index < loop->index20 || nd->index > loop->index24) && + nd->type != IROLinearLabel && + nd->type != IROLinearNop && + !(nd->flags & IROLF_Reffed) + ) + { + CError_ASSERT(345, nd->nodetype == EORASS || nd->nodetype == EANDASS || nd->nodetype == EXORASS); + + IRO_DuplicateExpr(pattern->nd0, &list); + nd1 = list.tail; + + shiftval = cint64_one; + shiftval = CInt64_Shl(shiftval, pattern->val1C); + + nd2 = IRO_NewLinear(IROLinearOperand); + nd2->index = ++IRO_NumLinear; + nd2->rtype = pattern->nd0->rtype; + expr = IRO_NewENode(EINTCONST); + expr->rtype = pattern->nd0->rtype; + CInt64_SetLong(&expr->data.intval, pass * CInt64_GetULong(&shiftval)); + nd2->u.node = expr; + IRO_AddToList(nd2, &list); + + IRO_DuplicateExpr(pattern->nd4, &list); + + nd3 = IRO_NewLinear(IROLinearOp2Arg); + nd3->index = ++IRO_NumLinear; + nd3->nodetype = EADD; + nd3->rtype = pattern->type; + nd3->u.diadic.left = list.tail; + nd3->u.diadic.right = nd2; + IRO_AddToList(nd3, &list); + + nd4 = IRO_NewLinear(IROLinearOp2Arg); + nd4->index = ++IRO_NumLinear; + nd4->nodetype = EADD; + nd4->rtype = pattern->type; + nd4->u.diadic.left = nd3; + nd4->u.diadic.right = nd1; + IRO_AddToList(nd4, &list); + + nd5 = IRO_NewLinear(IROLinearOp1Arg); + nd5->index = ++IRO_NumLinear; + nd5->nodetype = EINDIRECT; + nd5->rtype = nd->rtype; + nd5->u.monadic = nd4; + IRO_AddToList(nd5, &list); + + nd6 = IRO_NewLinear(IROLinearOp2Arg); + *nd6 = *nd; + nd6->index = ++IRO_NumLinear; + nd6->u.diadic.left = list.tail; + nd6->next = NULL; + + nd7 = IRO_NewLinear(IROLinearOperand); + nd7->index = ++IRO_NumLinear; + nd7->rtype = pattern->ndC->rtype; + expr = IRO_NewENode(EINTCONST); + expr->rtype = pattern->ndC->rtype; + nd7->u.node = expr; + nd7->next = NULL; + expr->data.intval = pattern->val14; + + if ( + IS_LINEAR_DIADIC(nd, EANDASS) && + CInt64_Equal(pattern->val14, cint64_zero) + ) + { + nd6->nodetype = EASS; + } else if ( + IS_LINEAR_DIADIC(nd, EORASS) && + !CTool_EndianReadWord32(&pattern->val14.hi) + ) + { + UInt32 tmp = CInt64_GetULong(&pattern->val14); + if ( + (nd->rtype->size == 1 && tmp == 0xFF) || + (nd->rtype->size == 2 && tmp == 0xFFFF) || + (nd->rtype->size == 4 && tmp == 0xFFFFFFFF) + ) + { + nd6->nodetype = EASS; + } + } + + IRO_AddToList(nd7, &list); + + if (IS_LINEAR_MONADIC(pattern->nd10, ETYPCON)) { + nd8 = IRO_NewLinear(IROLinearOp1Arg); + *nd8 = *pattern->nd10; + nd8->index = ++IRO_NumLinear; + nd8->u.monadic = nd7; + nd8->next = NULL; + IRO_AddToList(nd8, &list); + } else { + nd8 = nd7; + } + nd6->u.diadic.right = nd8; + IRO_AddToList(nd6, &list); + + if (!firstnode) + firstnode = list.head; + } + + if (nd == lastnd) + break; + nd = nd->next; + } + + if (list.head && list.tail) + IRO_Paste(list.head, list.tail, fnode2->last); + } + } while (++pass < 8); +} + +static int PatternMatchLoop(IRONode *fnode, IROLoop *loop, IROLoopInd *ind, UInt32 *unrollFactor, SInt32 *result1, SInt32 *result2, LoopPattern *pattern) { + IROLinear *scan; + IROLinear *varnode; + IROLinear *nd1; + IROLinear *nd2; + IROLinear *left1; + IROLinear *left2; + IROLinear *right1; + IROLinear *right2; + Object *obj1; + Object *obj2; + CInt64 shl; + CInt64 val; + + *result1 = 0; + *result2 = 0; + + if ((scan = fnode->first)) { + while (1) { + if ( + (scan->index < loop->index20 || scan->index > loop->index24) && + !(scan->flags & IROLF_Reffed) && + scan->type != IROLinearNop && + scan->type != IROLinearLabel + ) + { + if (IS_LINEAR_DIADIC_3(scan, EORASS, EXORASS, EANDASS)) { + (*result2)++; + if (IS_LINEAR_MONADIC(scan->u.diadic.left, EINDIRECT)) { + varnode = scan->u.diadic.left->u.monadic; + if (IS_LINEAR_DIADIC(varnode, EADD)) { + pattern->nd4 = varnode->u.diadic.left; + pattern->type = varnode->rtype; + if (IRO_IsVariable(varnode->u.diadic.left)) { + pattern->nd0 = varnode->u.diadic.right; + if ( + IS_LINEAR_DIADIC(pattern->nd0, ESHL) && + IRO_IsConstant(pattern->nd0->u.diadic.right) + ) + { + pattern->val1C = pattern->nd0->u.diadic.right->u.node->data.intval; + nd1 = pattern->nd0->u.diadic.left; + } else { + return 0; + } + } else { + return 0; + } + } else { + return 0; + } + } else { + return 0; + } + + pattern->nd10 = scan->u.diadic.right; + + if (IS_LINEAR_MONADIC(pattern->nd10, ETYPCON)) { + if (IS_LINEAR_DIADIC(scan, EANDASS)) { + if (IS_LINEAR_MONADIC(pattern->nd10->u.monadic, EBINNOT)) { + pattern->ndC = pattern->nd10->u.monadic->u.monadic; + } else { + return 0; + } + } else { + pattern->ndC = pattern->nd10->u.monadic; + } + + if (IS_LINEAR_DIADIC(pattern->ndC, ESHL) && IRO_IsConstant(pattern->ndC->u.diadic.left)) { + val = pattern->ndC->u.diadic.left->u.node->data.intval; + nd2 = pattern->ndC->u.diadic.right; + } else { + return 0; + } + } else if (IS_LINEAR_DIADIC(pattern->nd10, ESHL) && IS_LINEAR_DIADIC_2(scan, EORASS, EXORASS)) { + pattern->ndC = pattern->nd10; + if (IRO_IsConstant(pattern->ndC->u.diadic.left)) { + val = pattern->ndC->u.diadic.left->u.node->data.intval; + nd2 = pattern->ndC->u.diadic.right; + } else { + return 0; + } + } else if (IS_LINEAR_MONADIC(pattern->nd10, EBINNOT) && IS_LINEAR_DIADIC(scan, EANDASS)) { + pattern->ndC = pattern->nd10->u.monadic; + if (IS_LINEAR_DIADIC(pattern->ndC, ESHL) && IRO_IsConstant(pattern->ndC->u.diadic.left)) { + val = pattern->ndC->u.diadic.left->u.node->data.intval; + nd2 = pattern->ndC->u.diadic.right; + } else { + return 0; + } + } else { + return 0; + } + + if (IS_LINEAR_DIADIC(nd2, EAND) && IS_LINEAR_DIADIC(nd1, ESHR)) { + left1 = nd1->u.diadic.left; + left2 = nd2->u.diadic.left; + obj1 = IRO_IsVariable(left1); + obj2 = IRO_IsVariable(left2); + if (obj1 == obj2 && obj1 == ind->var->object) { + right1 = nd1->u.diadic.right; + right2 = nd2->u.diadic.right; + if (IRO_IsConstant(right1) && IRO_IsConstant(right2)) { + shl = cint64_one; + shl = CInt64_Shl(shl, right1->u.node->data.intval); + shl = CInt64_Sub(shl, cint64_one); + if (CInt64_Equal(shl, right2->u.node->data.intval)) { + if (CTool_EndianReadWord32(&shl.hi) == 0) { + *unrollFactor = CInt64_GetULong(&shl) + 1; + if (CheckConstant(CInt64_Add(shl, cint64_one), val, &pattern->val14)) { + (*result1)++; + if (IS_LINEAR_DIADIC(scan, EANDASS)) + pattern->val14 = CInt64_Not(pattern->val14); + } + } else { + return 0; + } + } else { + return 0; + } + } else { + return 0; + } + } else { + return 0; + } + } else { + return 0; + } + } else { + return 0; + } + } + + if (scan == fnode->last) + break; + scan = scan->next; + } + } + + return 1; +} + +static UInt32 UnrollWhileLoop(IRONode *header, IRONode *fnode2, IRONode *fnode3, IROLoop *loop, UInt32 unrollFactor) { + IROLoopInd *ind; + IRONode *scan; + CLabel *lastlabel; + IROLinear *lastlabelnode; + IROLinear *earlyLoopExitTest; + CLabel *earlyLoopExitTestLabel; + IROLinear *origIterationCount; + IROLinear *unrolledFinalValue; + IROLinear *preAlignTemp; + IROLinear *newFinalValue; + IROLinear *savedHead60; + IROLinear *unrolledBodyEntryTest; + CLabel *label; + IROLinear *savedHead2; + IROLinear *loophead25; + IROLinear *loopend; + IROLinear *loopscan; + IROLinear *indvar; + IROLinear *less; + IROLinear *loopExitTest; + IROLinear *saveTail; + CLabel *label2; + IROLinear *gotond; + CLabel *label3; + IROLinear *savedHead3; + IROLinear *updIndInc; + IROLinear *label2nd; + IROLinear *less2; + IROLinear *saveTail2; + IROLinear *less3; + IROLinear *wtf; + IROLinear *constnd; + IROLinear *ass; + IROLinear *nd18; + IRONode *fn19; + IRONode *newfnode1; + IRONode *newfnode2; + IRONode *newfnode3; + IRONode *newfnode4; + IRONode *newfnode5; + IRONode *newfnode6; + IRONode *newfnode7; + IRONode *newfnode8; + IROLinear *lastnd; + ENode *expr; + SInt32 result1; + SInt32 result2; + LoopPattern pattern; + IROList list; + + IRO_Dump("while(n--) loop \n"); + + if (loop->flags & LoopFlags_800) { + IRO_Dump("loop not unrolled because induction used in loop \n"); + return 0; + } + if (loop->flags & LoopFlags_1000) { + IRO_Dump("loop not unrolled because loop has multiple exits \n"); + return 0; + } + + if (!(loop->flags & LP_HAS_MULTIPLE_INDUCTIONS)) + return 0; + + for (ind = FirstInd; ind; ind = ind->next) { + if ((ind->flags & LoopInd_HasMod) && (ind->flags & LoopInd_HasDiv)) + break; + } + + if (!ind) { + IRO_Dump("Could not find loop with and induction with MOD and DIV operation\n"); + return 0; + } + + if (!IRO_IsUnsignedType(ind->nd->rtype)) + return 0; + + if (ind->nd->type == IROLinearOp2Arg) { + if (ind->nd->nodetype == EADDASS && IRO_IsConstant(ind->nd->u.diadic.right)) { + if (ind->addConst != 1) + return 0; + } else if (ind->nd->nodetype == EASS) { + if ( + ind->nd->u.diadic.right->type != IROLinearOp2Arg || + ind->nd->u.diadic.right->nodetype != EADD || + !IRO_IsConstant(ind->nd->u.diadic.right->u.diadic.right) + ) + return 0; + + if (ind->addConst != 1) + return 0; + } else { + return 0; + } + } else if (ind->nd->type == IROLinearOp1Arg && ind->nd->nodetype != EPREINC && ind->nd->nodetype != EPOSTINC) { + return 0; + } + + loop->induction = ind; + loop->index24 = ind->nd->index; + loop->index20 = IRO_FindStart(ind->nd)->index; + + scan = IRO_FirstNode; + memset(&pattern, 0, sizeof(pattern)); + while (scan) { + if (Bv_IsBitSet(scan->index, InLoop) && scan != header) { + if (!PatternMatchLoop(scan, loop, ind, &unrollFactor, &result1, &result2, &pattern)) + return 0; + } + scan = scan->nextnode; + } + + if (result1 > 1 || result2 > 1) + return 0; + + lastlabel = fnode2->last->u.label.label; + lastlabelnode = IRO_FindLabelNode(fnode2->last->u.label.label, fnode2->last); + + IRO_InitList(&list); + IRO_DuplicateExprRange(lastlabelnode->next, LoopNode->last->u.label.x4->u.diadic.left, &list); + IRO_DuplicateExpr(LoopNode->last->u.label.x4, &list); + IRO_Paste(list.head, list.tail, fnode2->last); + lastlabelnode = list.tail; + + IRO_InitList(&list); + earlyLoopExitTest = BuildEarlyLoopExitTest(LoopNode->last->type, &list); + earlyLoopExitTestLabel = IRO_NewLabel(); + earlyLoopExitTest->u.label.label = earlyLoopExitTestLabel; + earlyLoopExitTest->u.label.x4 = lastlabelnode; + earlyLoopExitTest->u.label.x4->flags |= IROLF_Reffed; + earlyLoopExitTest->rtype = LoopNode->last->rtype; + IRO_Paste(list.head, list.tail, fnode2->last); + + IRO_InitList(&list); + origIterationCount = BuildOrigIterationCount_DoWhile(&list, loop); + IRO_Paste(list.head, list.tail, fnode2->last); + savedHead60 = list.head; + + IRO_InitList(&list); + preAlignTemp = BuildPreAlignTemp(ind, unrollFactor, &list); + IRO_Paste(list.head, list.tail, fnode2->last); + + IRO_InitList(&list); + unrolledFinalValue = BuildUnrolledFinalvalue_DoWhile(origIterationCount, unrollFactor, &list, loop); + IRO_Paste(list.head, list.tail, fnode2->last); + + IRO_InitList(&list); + newFinalValue = BuildNewFinalvalue_DoWhile(origIterationCount, unrollFactor, &list, loop); + IRO_Paste(list.head, list.tail, fnode2->last); + + IRO_InitList(&list); + BuildUnrolledBodyEntryTest(&list, origIterationCount, unrollFactor, lastlabel); + IRO_Paste(list.head, list.tail, fnode2->last); + unrolledBodyEntryTest = list.tail; + + IRO_InitList(&list); + label = BuildLabel(&list); + IRO_Paste(list.head, list.tail, fnode2->last); + + savedHead2 = list.head; + loophead25 = NULL; + for (scan = fnode3; scan && scan != header; scan = scan->nextnode) { + IRO_InitList(&list); + loopend = scan->last; + loopscan = scan->first; + while (1) { + if (loopscan->stmt) + loopscan->stmt->flags |= StmtFlag_10; + if (loopscan->type != IROLinearLabel && !(loopscan->flags & IROLF_Reffed)) { + IRO_DuplicateExpr(loopscan, &list); + if (!loophead25) + loophead25 = list.head; + } + if (loopscan == loopend) + break; + loopscan = loopscan->next; + } + + if (list.head && list.tail) + IRO_Paste(list.head, list.tail, fnode2->last); + } + + IRO_InitList(&list); + + if (ind->nd->type == IROLinearOp1Arg) + IRO_DuplicateExpr(ind->nd->u.monadic, &list); + else + IRO_DuplicateExpr(ind->nd->u.diadic.left, &list); + list.tail->flags &= ~IROLF_Assigned; + indvar = list.tail; + + IRO_DuplicateExpr(preAlignTemp, &list); + list.tail->flags &= ~IROLF_Assigned; + + less = IRO_NewLinear(IROLinearOp2Arg); + less->nodetype = ELESS; + less->rtype = TYPE(&stbool); + less->index = ++IRO_NumLinear; + less->next = NULL; + less->u.diadic.left = indvar; + less->u.diadic.right = list.tail; + IRO_AddToList(less, &list); + less->flags |= IROLF_Reffed; + + loopExitTest = BuildLoopExitTest(LoopNode->last->type, &list); + loopExitTest->u.label.label = label; + loopExitTest->u.label.x4 = less; + loopExitTest->u.label.x4->flags |= IROLF_Reffed; + loopExitTest->rtype = LoopNode->last->rtype; + IRO_Paste(list.head, list.tail, fnode2->last); + saveTail = list.tail; + + IRO_InitList(&list); + label2 = IRO_NewLabel(); + gotond = IRO_NewLinear(IROLinearOp1Arg); + gotond->index = ++IRO_NumLinear; + gotond->type = IROLinearGoto; + gotond->u.label.label = label2; + IRO_AddToList(gotond, &list); + IRO_Paste(list.head, list.tail, fnode2->last); + + IRO_InitList(&list); + label3 = BuildLabel(&list); + IRO_Paste(list.head, list.tail, fnode2->last); + savedHead3 = list.head; + + UnrollWhileLoopBody(header, fnode2, fnode3, loop, &pattern, unrollFactor); + updIndInc = UpdateInductionIncrement(loop, 8 * unrollFactor, fnode2->last); + + IRO_InitList(&list); + label2nd = IRO_NewLinear(IROLinearLabel); + label2nd->index = IRO_NumLinear++; + label2nd->u.label.label = label2; + label2nd->flags |= IROLF_1; + IRO_AddToList(label2nd, &list); + IRO_Paste(list.head, list.tail, fnode2->last); + + IRO_InitList(&list); + + if (ind->nd->type == IROLinearOp1Arg) + IRO_DuplicateExpr(ind->nd->u.monadic, &list); + else + IRO_DuplicateExpr(ind->nd->u.diadic.left, &list); + list.tail->flags &= ~IROLF_Assigned; + indvar = list.tail; + + IRO_DuplicateExpr(unrolledFinalValue, &list); + list.tail->flags &= ~IROLF_Assigned; + + less2 = IRO_NewLinear(IROLinearOp2Arg); + less2->nodetype = ELESS; + less2->rtype = TYPE(&stbool); + less2->index = ++IRO_NumLinear; + less2->next = NULL; + less2->u.diadic.left = indvar; + less2->u.diadic.right = list.tail; + IRO_AddToList(less2, &list); + less2->flags |= IROLF_Reffed; + + loopExitTest = BuildLoopExitTest(LoopNode->last->type, &list); + loopExitTest->u.label.label = label3; + loopExitTest->u.label.x4 = less2; + loopExitTest->u.label.x4->flags |= IROLF_Reffed; + loopExitTest->rtype = LoopNode->last->rtype; + IRO_Paste(list.head, list.tail, fnode2->last); + saveTail2 = list.tail; + + IRO_InitList(&list); + + if (ind->nd->type == IROLinearOp1Arg) + IRO_DuplicateExpr(ind->nd->u.monadic, &list); + else + IRO_DuplicateExpr(ind->nd->u.diadic.left, &list); + list.tail->flags &= ~IROLF_Assigned; + indvar = list.tail; + + IRO_DuplicateExpr(newFinalValue, &list); + list.tail->flags &= ~IROLF_Assigned; + + less3 = IRO_NewLinear(IROLinearOp2Arg); + less3->nodetype = ELESS; + less3->rtype = TYPE(&stbool); + less3->index = ++IRO_NumLinear; + less3->next = NULL; + less3->u.diadic.left = indvar; + less3->u.diadic.right = list.tail; + IRO_AddToList(less3, &list); + less3->flags |= IROLF_Reffed; + + wtf = LoopNode->last->u.label.x4; + IRO_Paste(list.head, list.tail, LoopNode->last); + LoopNode->last->u.label.x4 = list.tail; + + IRO_InitList(&list); + + constnd = IRO_NewLinear(IROLinearOperand); + constnd->index = ++IRO_NumLinear; + expr = IRO_NewENode(EINTCONST); + expr->rtype = wtf->u.diadic.left->rtype; + expr->data.intval = cint64_zero; + constnd->u.node = expr; + constnd->rtype = expr->rtype; + IRO_AddToList(constnd, &list); + constnd->flags |= IROLF_Reffed; + + IRO_DuplicateExpr(wtf->u.diadic.left, &list); + + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->nodetype = EASS; + ass->rtype = list.tail->rtype; + ass->index = ++IRO_NumLinear; + ass->next = NULL; + ass->u.diadic.left = list.tail; + ass->u.diadic.right = constnd; + IRO_AddToList(ass, &list); + ass->flags |= IROLF_Assigned; + + IRO_NopOut(wtf); + + fn19 = fnode2->nextnode; + nd18 = fnode2->last; + fnode2->last = earlyLoopExitTest; + + newfnode1 = IRO_NewFlowGraphNode(); + newfnode1->first = savedHead60; + newfnode1->last = unrolledBodyEntryTest; + fnode2->nextnode = newfnode1; + + newfnode2 = IRO_NewFlowGraphNode(); + newfnode2->first = savedHead2; + newfnode2->last = saveTail; + savedHead2->u.label.label->stmt = (Statement *) newfnode2; + newfnode1->nextnode = newfnode2; + + newfnode3 = IRO_NewFlowGraphNode(); + newfnode3->first = gotond; + newfnode3->last = gotond; + newfnode2->nextnode = newfnode3; + + newfnode4 = IRO_NewFlowGraphNode(); + newfnode4->first = savedHead3; + newfnode4->last = updIndInc; + savedHead3->u.label.label->stmt = (Statement *) newfnode4; + newfnode3->nextnode = newfnode4; + + newfnode5 = IRO_NewFlowGraphNode(); + newfnode5->first = label2nd; + newfnode5->last = saveTail2; + label2nd->u.label.label->stmt = (Statement *) newfnode5; + newfnode4->nextnode = newfnode5; + + newfnode6 = IRO_NewFlowGraphNode(); + newfnode6->first = nd18; + newfnode6->last = nd18; + newfnode5->nextnode = newfnode6; + newfnode6->nextnode = fn19; + + newfnode7 = oalloc(sizeof(IRONode)); + memset(newfnode7, 0, sizeof(IRONode)); + newfnode7->index = IRO_NumNodes; + IRO_NumNodes++; + + newfnode7->first = list.head; + newfnode7->last = list.tail; + + list.tail->next = LoopNode->last->next; + LoopNode->last->next = list.head; + + newfnode7->nextnode = LoopNode->nextnode; + LoopNode->nextnode = newfnode7; + + newfnode8 = oalloc(sizeof(IRONode)); + memset(newfnode8, 0, sizeof(IRONode)); + newfnode8->index = IRO_NumNodes; + IRO_NumNodes++; + + lastnd = IRO_NewLinear(IROLinearLabel); + lastnd->index = IRO_NumLinear++; + lastnd->next = NULL; + lastnd->u.label.label = earlyLoopExitTestLabel; + lastnd->flags |= IROLF_1; + earlyLoopExitTestLabel->stmt = (Statement *) newfnode8; + + newfnode8->first = lastnd; + newfnode8->last = lastnd; + + lastnd->next = newfnode7->last->next; + newfnode7->last->next = lastnd; + + newfnode8->nextnode = newfnode7->nextnode; + newfnode7->nextnode = newfnode8; + + return 1; +} + +void IRO_IterateForLoopBody(IRONode *start, IRONode *end, IROLoop *loop, IROLinear *destnode, SInt32 addConst, CInt64 *val, Boolean funkyFlag) { + IROLinear *first = NULL; + IROLinear *last = NULL; + IRONode *fnode; + IROLinear *lastnd; + IROLinear *nd; + IROList list; + + for (fnode = start; fnode && fnode != end; fnode = fnode->nextnode) { + IRO_InitList(&list); + + lastnd = fnode->last; + nd = fnode->first; + while (1) { + if (nd->stmt) + nd->stmt->flags |= StmtFlag_10; + + if ( + (nd->index < loop->index20 || nd->index > loop->index24) && + nd->type != IROLinearLabel && + !(nd->flags & IROLF_Reffed) + ) + { + IRO_DuplicateExpr(nd, &list); + if (!first) + first = list.head; + last = list.tail; + } + + if (nd == lastnd) + break; + nd = nd->next; + } + + if (list.head && list.tail) + IRO_Paste(list.head, list.tail, destnode); + } + + if (funkyFlag) { + *val = CInt64_Add(*val, IRO_MakeLong(loop->induction->addConst)); + ChangeInductionReference(first, last, *val, loop); + } +} + +void IRO_LinearizeForLoopPostLoop(IRONode *fnode1, IRONode *fnode2, IROLoop *loop, IRONode *fnode3, UInt32 unrollFactor) { + IRONode *newfnode; + IROLinear *newnd; + SInt32 i; + CInt64 val; + + newfnode = oalloc(sizeof(IRONode)); + memset(newfnode, 0, sizeof(IRONode)); + newfnode->index = IRO_NumNodes; + IRO_NumNodes++; + + newnd = IRO_NewLinear(IROLinearNop); + newnd->index = IRO_NumLinear++; + newnd->next = NULL; + newnd->flags |= IROLF_1; + + newfnode->first = newfnode->last = newnd; + + newfnode->nextnode = fnode3->nextnode; + fnode3->nextnode = newfnode; + + newnd->next = fnode3->last->next; + fnode3->last->next = newnd; + + val = cint64_zero; + for (i = 0; i < unrollFactor; i++) + IRO_IterateForLoopBody(fnode2, fnode1, loop, newfnode->last, loop->induction->addConst, &val, i > 0); + UpdateInductionIncrement(loop, unrollFactor, newfnode->last); +} + +static UInt32 UnrollForLoop(IRONode *header, IRONode *fnode2, IRONode *fnode3, IROLoop *loop, UInt32 unrollFactor) { + IROLinear *lastlabelnode; + IROLinear *earlyLoopExitTest; + IROLinear *origIterationCount; + IROLinear *saveHead1; + IROLinear *newFinalValue; + IROLinear *unrolledBodyEntryTest; + IROLinear *gotoNd; + IROLinear *saveHead2; + IROLinear *updIndInc; + IROLinear *labelNd; + IROLinear *saveTail2; + IROLinear *ndCopy; + IROLinear *saveTail3; + IROLinear *loopExitTest; + IROLinear *lastnd; + IROLinear *labelNd2; + IROLinear *saveTail4; + IROLinear *labelNd3; + IROLinear *scan; + IRONode *nd18; + IRONode *newfnode1; + IRONode *newfnode2; + IRONode *newfnode3; + IRONode *newfnode4; + IRONode *newfnode5; + IRONode *newfnode6; + CLabel *lastlabel; + CLabel *earlyLoopExitTestLabel; + CLabel *label; + CLabel *label2; + SInt32 i; + + IROList list; + CInt64 iterCount; + int isConstant; + UInt32 needOrigLoop = 0; + UInt32 needUnrollBodyTest = 0; + UInt32 resetUnrolledFinalValue = 0; + SInt32 leftOver; + CInt64 val; + + lastlabelnode = IRO_FindLabelNode(fnode2->last->u.label.label, fnode2->last); + lastlabel = IRO_NewLabel(); + + IRO_InitList(&list); + IRO_DuplicateExprRange(lastlabelnode->next, LoopNode->last->u.label.x4, &list); + IRO_DuplicateExpr(LoopNode->last->u.label.x4, &list); + IRO_Paste(list.head, list.tail, fnode2->last); + lastlabelnode = list.tail; + + IRO_InitList(&list); + earlyLoopExitTest = BuildEarlyLoopExitTest(LoopNode->last->type, &list); + earlyLoopExitTestLabel = IRO_NewLabel(); + earlyLoopExitTest->u.label.label = earlyLoopExitTestLabel; + earlyLoopExitTest->u.label.x4 = lastlabelnode; + earlyLoopExitTest->u.label.x4->flags |= IROLF_Reffed; + earlyLoopExitTest->rtype = LoopNode->last->rtype; + IRO_Paste(list.head, list.tail, fnode2->last); + + isConstant = IsIterationCountConstant(loop, &iterCount); + needOrigLoop = 1; + needUnrollBodyTest = 1; + resetUnrolledFinalValue = 0; + if (isConstant) + IRO_TestConstantIterationCount(loop, &iterCount, 1, &unrollFactor, &leftOver, &needOrigLoop, &needUnrollBodyTest, &resetUnrolledFinalValue); + + IRO_InitList(&list); + origIterationCount = BuildOrigIterationCount(&list, loop); + IRO_Paste(list.head, list.tail, fnode2->last); + saveHead1 = list.head; + + IRO_InitList(&list); + newFinalValue = BuildNewFinalvalue(origIterationCount, unrollFactor, &list, loop); + IRO_Paste(list.head, list.tail, fnode2->last); + + IRO_InitList(&list); + BuildUnrolledBodyEntryTest(&list, origIterationCount, unrollFactor, lastlabel); + IRO_Paste(list.head, list.tail, fnode2->last); + unrolledBodyEntryTest = list.tail; + + label = IRO_NewLabel(); + IRO_InitList(&list); + gotoNd = IRO_NewLinear(IROLinearOp1Arg); + gotoNd->index = ++IRO_NumLinear; + gotoNd->type = IROLinearGoto; + gotoNd->u.label.label = label; + IRO_AddToList(gotoNd, &list); + IRO_Paste(list.head, list.tail, fnode2->last); + + IRO_InitList(&list); + label2 = BuildLabel(&list); + IRO_Paste(list.head, list.tail, fnode2->last); + saveHead2 = list.head; + + val = cint64_zero; + for (i = 0; i < unrollFactor; i++) + IRO_IterateForLoopBody(fnode3, header, loop, fnode2->last, loop->induction->addConst, &val, i > 0); + updIndInc = UpdateInductionIncrement(loop, unrollFactor, fnode2->last); + + IRO_InitList(&list); + labelNd = IRO_NewLinear(IROLinearLabel); + labelNd->index = IRO_NumLinear++; + labelNd->u.label.label = label; + labelNd->flags |= IROLF_1; + IRO_AddToList(labelNd, &list); + IRO_Paste(list.head, list.tail, fnode2->last); + + IRO_InitList(&list); + + IRO_DuplicateExpr(LoopNode->last->u.label.x4->u.diadic.left, &list); + saveTail2 = list.tail; + + if (resetUnrolledFinalValue) + IRO_DuplicateExpr(loop->nd18->u.diadic.right, &list); + else + IRO_DuplicateExpr(newFinalValue, &list); + + ndCopy = IRO_NewLinear(LoopNode->last->u.label.x4->type); + *ndCopy = *LoopNode->last->u.label.x4; + ndCopy->index = ++IRO_NumLinear; + ndCopy->next = NULL; + ndCopy->expr = NULL; + ndCopy->u.diadic.left = saveTail2; + ndCopy->u.diadic.right = list.tail; + IRO_AddToList(ndCopy, &list); + + IRO_Paste(list.head, list.tail, fnode2->last); + saveTail3 = list.tail; + + IRO_InitList(&list); + loopExitTest = BuildLoopExitTest(LoopNode->last->type, &list); + loopExitTest->u.label.label = label2; + loopExitTest->u.label.x4 = saveTail3; + loopExitTest->u.label.x4->flags |= IROLF_Reffed; + loopExitTest->rtype = LoopNode->last->rtype; + IRO_Paste(list.head, list.tail, fnode2->last); + saveTail4 = list.tail; + + IRO_InitList(&list); + labelNd2 = IRO_NewLinear(IROLinearLabel); + labelNd2->index = IRO_NumLinear++; + labelNd2->u.label.label = lastlabel; + labelNd2->flags |= IROLF_1; + IRO_AddToList(labelNd2, &list); + IRO_Paste(list.head, list.tail, fnode2->last); + + lastnd = fnode2->last; + nd18 = fnode2->nextnode; + fnode2->last = earlyLoopExitTest; + + newfnode1 = IRO_NewFlowGraphNode(); + newfnode1->first = saveHead1; + newfnode1->last = unrolledBodyEntryTest; + fnode2->nextnode = newfnode1; + + newfnode2 = IRO_NewFlowGraphNode(); + newfnode2->first = gotoNd; + newfnode2->last = gotoNd; + newfnode1->nextnode = newfnode2; + + newfnode3 = IRO_NewFlowGraphNode(); + newfnode3->first = saveHead2; + newfnode3->last = updIndInc; + + saveHead2->u.label.label->stmt = (Statement *) newfnode3; + if (newfnode2) + newfnode2->nextnode = newfnode3; + else + newfnode1->nextnode = newfnode3; + + newfnode4 = IRO_NewFlowGraphNode(); + newfnode4->first = labelNd; + newfnode4->last = saveTail4; + labelNd->u.label.label->stmt = (Statement *) newfnode4; + newfnode3->nextnode = newfnode4; + + newfnode5 = IRO_NewFlowGraphNode(); + newfnode5->first = labelNd2; + newfnode5->last = lastnd; + newfnode4->nextnode = newfnode5; + newfnode5->nextnode = nd18; + + newfnode6 = oalloc(sizeof(IRONode)); + memset(newfnode6, 0, sizeof(IRONode)); + newfnode6->index = IRO_NumNodes; + IRO_NumNodes++; + + labelNd3 = IRO_NewLinear(IROLinearLabel); + labelNd3->index = IRO_NumLinear++; + labelNd3->next = NULL; + labelNd3->u.label.label = earlyLoopExitTestLabel; + labelNd3->flags |= IROLF_1; + earlyLoopExitTestLabel->stmt = (Statement *) newfnode6; + + newfnode6->first = labelNd3; + newfnode6->last = labelNd3; + + labelNd3->next = LoopNode->last->next; + LoopNode->last->next = labelNd3; + + newfnode6->nextnode = LoopNode->nextnode; + LoopNode->nextnode = newfnode6; + + if (!needOrigLoop) { + NoOpBlock(newfnode5); + NoOpBlock(header); + NoOpBlock(fnode3); + NoOpBlock(loop->induction->fnode); + IRO_NopOut(newfnode1->last->u.label.x4); + newfnode1->last->type = IROLinearNop; + } + + if (!needUnrollBodyTest) { + IRO_NopOut(earlyLoopExitTest->u.label.x4); + earlyLoopExitTest->type = IROLinearNop; + + IRO_NopOut(newfnode4->last->u.label.x4); + newfnode4->last->type = IROLinearNop; + + if (newfnode2) + newfnode2->last->type = IROLinearNop; + + for (scan = newfnode1->first; scan; scan = scan->next) { + if (!(scan->flags & IROLF_Reffed)) + IRO_NopOut(scan); + if (scan == newfnode1->last) + break; + } + } + + return 1; +} + +static UInt32 UnrollStandardLoop(IRONode *header, IRONode *fnode2, IRONode *fnode3, int count) { + IROLoop *loop; + + ConditionalHeaderAtBottom = 1; + loop = ExtractLoopInfo(header); + loop->xC = fnode2; + loop->x10 = fnode3; + FindAssignmenttoInductionVar(loop, fnode2); + + if (!IsLoopUnrollable(loop)) { + IRO_Dump("LoopUnroll:loop with header %d not unrolled because IsLoopUnrollable failed\n", header->index); + return 0; + } + + if (loop->flags & LoopFlags_10000) + return UnrollWhileLoop(header, fnode2, fnode3, loop, count); + else + return UnrollForLoop(header, fnode2, fnode3, loop, count); +} + +static void LoopUnroll(int count, IRONode *header) { + VarRecord *var; + IRONode *tmp; + UInt16 i; + UInt16 j; + IRONode *prevpred; + IRONode *prevsucc; + int foundpred; + UInt32 predcount; + UInt32 success = 0; + + LoopNode = header; + FindMustReach(); + + for (var = IRO_FirstVar; var; var = var->next) + var->xA = 1; + + ComputeLoopKills(); + ComputeLoopInvariance(); + ComputeLoopInduction(); + + LoopNode = header; + ConditionalHeaderAtBottom = 0; + + prevpred = NULL; + foundpred = 0; + for (i = 0; i < LoopNode->numpred; i++) { + tmp = IRO_NodeTable[LoopNode->pred[i]]; + if (!Bv_IsBitSet(tmp->index, InLoop)) { + foundpred = 1; + if (tmp->nextnode == header) { + CError_ASSERT(2101, !prevpred || tmp == prevpred); + prevpred = tmp; + } + } + } + + if (!foundpred) { + IRO_Dump("No predecessor outside the loop\n"); + return; + } + + if (LoopNode->last->type == IROLinearIf || LoopNode->last->type == IROLinearIfNot) { + if (LoopNode->nextnode && !Bv_IsBitSet(LoopNode->nextnode->index, InLoop)) { + prevsucc = NULL; + for (i = 0; i < LoopNode->numsucc; i++) { + tmp = IRO_NodeTable[LoopNode->succ[i]]; + if (Bv_IsBitSet(tmp->index, InLoop)) { + CError_ASSERT(2159, !prevsucc); + prevsucc = tmp; + } + } + + prevpred = NULL; + predcount = 0; + for (j = 0; j < LoopNode->numpred; j++) { + tmp = IRO_NodeTable[LoopNode->pred[j]]; + if (!Bv_IsBitSet(tmp->index, InLoop)) { + prevpred = tmp; + predcount++; + } + } + + if ( + predcount == 1 && + prevpred->last->type == IROLinearGoto && + prevpred->nextnode == prevsucc && + prevsucc != LoopNode + ) + { + success = UnrollStandardLoop(header, prevpred, prevsucc, count); + } + } + } else { + IRO_Dump(" LoopUnroll:Loop with header = %d is not a conditional loop\n", header->index); + } + + if (!success) + return; + + IRO_NodeTable = oalloc(sizeof(IRONode *) * IRO_NumNodes); + memset(IRO_NodeTable, 0, sizeof(IRONode *) * IRO_NumNodes); + for (tmp = IRO_FirstNode; tmp; tmp = tmp->nextnode) + IRO_NodeTable[tmp->index] = tmp; + IRO_ComputeSuccPred(); + IRO_ComputeDom(); + if (success) + IRO_Dump(" LoopUnroll:Loop with header = %d Unrolled\n", header->index); +} + +static int IsLoopUnrollable(IROLoop *loop) { + CInt64 tmp; + + if (loop->flags & LP_LOOP_HAS_ASM) { + IRO_Dump("IsLoopUnrollable:No due to LP_LOOP_HAS_ASM \n"); + return 0; + } + if (loop->flags & LP_IFEXPR_NON_CANONICAL) { + IRO_Dump("IsLoopUnrollable:No due to LP_IFEXPR_NON_CANONICAL \n"); + return 0; + } + if (loop->flags & LP_LOOP_HAS_CALLS) { + IRO_Dump("IsLoopUnrollable:No due to LP_LOOP_HAS_CALLS \n"); + return 0; + } + if (loop->flags & LP_LOOP_HAS_CNTRLFLOW) { + IRO_Dump("IsLoopUnrollable:No due to LP_LOOP_HAS_CNTRLFLOW \n"); + return 0; + } + if (loop->flags & LP_INDUCTION_NOT_FOUND) { + IRO_Dump("IsLoopUnrollable:No due to LP_INDUCTION_NOT_FOUND \n"); + return 0; + } + if (loop->flags & LP_LOOP_HDR_HAS_SIDEEFFECTS) { + IRO_Dump("IsLoopUnrollable:No due to LP_LOOP_HDR_HAS_SIDEEFFECTS \n"); + return 0; + } + if (!(loop->flags & LoopFlags_200)) { + IRO_Dump("IsLoopUnrollable:No because header does not follow induction update \n"); + return 0; + } + + if (!(loop->flags & LoopFlags_10000)) { + IROLinear *upperBound = loop->nd18->u.diadic.right; + if (!IRO_IsIntConstant(upperBound) && !(upperBound->flags & IROLF_LoopInvariant)) { + IRO_Dump("IsLoopUnrollable:No because Loop Upper Bound is Variant in the loop\n"); + return 0; + } + if (!loop->nd14) { + IRO_Dump("IsLoopUnrollable:No because there is no initialization of loop index in PreHeader\n"); + return 0; + } + if (!IRO_IsVariable(loop->nd14->u.diadic.left)) { + IRO_Dump("IsLoopUnrollable:No because initial value of induction stored thru pointer\n"); + return 0; + } + + if (!IRO_IsUnsignedType(loop->nd14->rtype)) { + if (IRO_IsIntConstant(loop->nd14->u.diadic.right)) { + if (!CInt64_GreaterEqual(loop->nd14->u.diadic.right->u.node->data.intval, cint64_zero)) { + IRO_Dump("IsLoopUnrollable:No because initial value of induction is signed but init < 0\n"); + return 0; + } + } else if (IsIterationCountConstant(loop, &tmp)) { + IRO_Dump("IsLoopUnrollable:Yes, the limits substract out to be constants\n"); + } else { + IRO_Dump("IsLoopUnrollable:No because initial value of induction is signed and not constant\n"); + return 0; + } + } + + if (!(loop->flags & LP_LOOP_STEP_ISADD)) { + IRO_Dump("IsLoopUnrollable:No because LP_LOOP_STEP_ISADD is not set i.e induciton is not updated by 1\n"); + return 0; + } + + } else { + if (!IRO_IsUnsignedType(loop->nd18->u.diadic.left->rtype)) { + IRO_Dump("IsLoopUnrollable:No because the while loop induction is signed\n"); + return 0; + } + if (!(loop->flags & LoopFlags_2000)) { + IRO_Dump("IsLoopUnrollable:No because the while loop operator is not of decrement form\n"); + return 0; + } + } + + if (loop->sizeBySomeMeasurement > copts.unrollinstrfactor) { + IRO_Dump("IsLoopUnrollable:No because loop size greater than threshold\n"); + return 0; + } + + return 1; +} + +IROLinear *BuildEarlyLoopExitTest(IROLinearType type, IROList *list) { + IROLinear *nd = IRO_NewLinear(IROLinearOp1Arg); + nd->index = ++IRO_NumLinear; + if (type == IROLinearIf) + nd->type = IROLinearIfNot; + else + nd->type = IROLinearIf; + IRO_AddToList(nd, list); + return nd; +} + +IROLinear *BuildLoopExitTest(IROLinearType type, IROList *list) { + IROLinear *nd = IRO_NewLinear(IROLinearOp1Arg); + nd->index = ++IRO_NumLinear; + nd->type = type; + IRO_AddToList(nd, list); + return nd; +} + +int IsIterationCountConstant(IROLoop *loop, CInt64 *pval) { + IROLinear *lowerBound; + IROLinear *upperBound; + Type *type; + int isUnsigned; + IROAddrRecord *lowerRec; + IROAddrRecord *upperRec; + CInt64 lowerval; + CInt64 upperval; + CInt64 incval; + CInt64 negOne; + + lowerBound = loop->nd14->u.diadic.right; + if (loop->flags & LoopFlags_1) { + upperBound = loop->nd18->u.diadic.right; + type = loop->nd18->u.diadic.right->rtype; + } else { + upperBound = loop->nd18->u.diadic.left; + type = loop->nd18->u.diadic.left->rtype; + } + + isUnsigned = IRO_IsUnsignedType(type); + + if (IRO_IsIntConstant(lowerBound) && IRO_IsIntConstant(upperBound)) { + lowerval = lowerBound->u.node->data.intval; + upperval = upperBound->u.node->data.intval; + if (isUnsigned) { + if (CInt64_LessEqualU(upperval, lowerval)) + return 0; + } else { + if (CInt64_LessEqual(upperval, lowerval)) + return 0; + } + + CInt64_SetLong(&incval, loop->induction->addConst); + CInt64_SetLong(&negOne, -1); + *pval = CInt64_Sub(upperval, lowerval); + *pval = CInt64_Add(*pval, incval); + + if (IS_LINEAR_DIADIC(loop->nd18, ELESS)) + *pval = CInt64_Add(*pval, negOne); + + CError_ASSERT(2486, !CInt64_IsZero(&incval)); + + if (isUnsigned) + *pval = CInt64_DivU(*pval, incval); + else + *pval = CInt64_Div(*pval, incval); + + if (CInt64_Equal(*pval, cint64_zero)) + return 0; + + if (isUnsigned) { + CError_ASSERT(2508, !CInt64_LessEqualU(*pval, cint64_zero)); + } else { + CError_ASSERT(2517, !CInt64_LessEqual(*pval, cint64_zero)); + } + + return 1; + } + + lowerRec = IRO_InitAddrRecordPointer(lowerBound); + upperRec = IRO_InitAddrRecordPointer(upperBound); + + if (IS_LINEAR_DIADIC(lowerBound, EADD)) { + IRO_DecomposeAddressExpression(lowerBound, lowerRec); + } else if (IRO_IsIntConstant(lowerBound)) { + lowerRec->numInts++; + IRO_AddElmToList(lowerBound, &lowerRec->ints); + lowerRec->numObjRefs = 0; + lowerRec->numMisc = 0; + } else { + lowerRec->numMisc++; + IRO_AddElmToList(lowerBound, &lowerRec->misc); + lowerRec->numObjRefs = 0; + lowerRec->numInts = 0; + } + + if (IS_LINEAR_DIADIC(upperBound, EADD)) { + IRO_DecomposeAddressExpression(upperBound, upperRec); + } else if (IRO_IsIntConstant(upperBound)) { + upperRec->numInts++; + IRO_AddElmToList(upperBound, &upperRec->ints); + upperRec->numObjRefs = 0; + upperRec->numMisc = 0; + } else { + upperRec->numMisc++; + IRO_AddElmToList(upperBound, &upperRec->misc); + upperRec->numObjRefs = 0; + upperRec->numInts = 0; + } + + if (IsDifferenceOfTermsConstant(lowerRec, upperRec, isUnsigned, pval)) { + if (IS_LINEAR_DIADIC(loop->nd18, ELESSEQU)) + *pval = CInt64_Add(*pval, cint64_one); + return 1; + } + + return 0; +} + +static int IsDifferenceOfTermsConstant(IROAddrRecord *lowerRec, IROAddrRecord *upperRec, int isUnsigned, CInt64 *pval) { + UInt32 i; + CInt64 upperval; + CInt64 lowerval; + IROElmList *el; + IROLinear *nd; + + if (upperRec->numObjRefs == lowerRec->numObjRefs && upperRec->numObjRefs != 0) + return 0; + else if (upperRec->numObjRefs != lowerRec->numObjRefs) + return 0; + + if (upperRec->numMisc == lowerRec->numMisc && upperRec->numMisc != 0) { + for (i = 0; i < upperRec->numMisc; i++) { + // bug? surely this should index on i...? + if (!IRO_ExprsSame(lowerRec->misc->element, upperRec->misc->element)) + return 0; + } + } else if (upperRec->numMisc != lowerRec->numMisc) { + return 0; + } + + upperval = cint64_zero; + for (el = upperRec->ints; el; el = el->next) { + nd = el->element; + upperval = CMach_CalcIntDiadic(nd->rtype, upperval, '+', nd->u.node->data.intval); + } + + lowerval = cint64_zero; + for (el = lowerRec->ints; el; el = el->next) { + nd = el->element; + lowerval = CMach_CalcIntDiadic(nd->rtype, lowerval, '+', nd->u.node->data.intval); + } + + if (CInt64_Equal(upperval, lowerval)) + return 0; + + if (CInt64_Greater(upperval, lowerval)) { + *pval = CInt64_Sub(upperval, lowerval); + return 1; + } else { + return 0; + } +} + +void NoOpBlock(IRONode *fnode) { + IROLinear *last, *scan; + + for (scan = fnode->first, last = fnode->last; scan; scan = scan->next) { + scan->type = IROLinearNop; + if (scan == last) + break; + } +} + +void IRO_TestConstantIterationCount(IROLoop *loop, CInt64 *iterCount, SInt32 vectorStride, UInt32 *unrollFactor, SInt32 *leftOver, UInt32 *needOrigLoop, UInt32 *needUnrollBodyTest, UInt32 *resetUnrolledFinalValue) { + UInt32 isUnsigned; + CInt64 val; + CInt64 val3; + CInt64 mod; + CInt64 val2; + CInt64 loopvar3; + CInt64 loopvar1; + CInt64 loopvar2; + CInt64 strideVal; + + CError_ASSERT(2737, *unrollFactor); + + isUnsigned = IRO_IsUnsignedType( + (loop->flags & LoopFlags_1) ? loop->nd18->u.diadic.right->rtype :loop->nd18->u.diadic.left->rtype); + + CError_ASSERT(2756, vectorStride); + + strideVal = IRO_MakeLong(vectorStride); + if (isUnsigned ? CInt64_LessU(*iterCount, strideVal) : CInt64_Less(*iterCount, strideVal)) { + *needOrigLoop = 1; + *needUnrollBodyTest = 0; + *unrollFactor = 0; + *leftOver = CInt64_GetULong(iterCount); + } else { + switch (vectorStride) { + case 1: + val = *iterCount; + break; + case 2: + val = CInt64_ShrU(*iterCount, cint64_one); + break; + case 4: + val = CInt64_ShrU(*iterCount, IRO_MakeLong(2)); + break; + case 8: + val = CInt64_ShrU(*iterCount, IRO_MakeLong(3)); + break; + case 16: + val = CInt64_ShrU(*iterCount, IRO_MakeLong(4)); + break; + default: + val = CInt64_Div(*iterCount, strideVal); + } + + if (CInt64_LessU(val, IRO_MakeLong(*unrollFactor))) + *unrollFactor = CInt64_GetULong(&val); + + CInt64_SetLong(&val2, *unrollFactor); + switch (vectorStride) { + case 1: + val3 = cint64_zero; + break; + case 2: + val3 = CInt64_And(*iterCount, cint64_one); + break; + case 4: + val3 = CInt64_And(*iterCount, IRO_MakeLong(3)); + break; + case 8: + val3 = CInt64_And(*iterCount, IRO_MakeLong(7)); + break; + case 16: + val3 = CInt64_And(*iterCount, IRO_MakeLong(15)); + break; + default: + val3 = CInt64_Mod(*iterCount, strideVal); + } + + if (CInt64_LessEqualU(val, IRO_MakeLong(8))) { + *needUnrollBodyTest = vectorStride > 1; + *unrollFactor = CInt64_GetULong(&val); + *leftOver = CInt64_GetULong(&val3); + *needOrigLoop = *leftOver != 0; + *resetUnrolledFinalValue = !(*needOrigLoop && *needUnrollBodyTest); + } else { + loopvar1 = IRO_MakeLong(0x7FFFFFFF); + loopvar2 = IRO_MakeLong(0x7FFFFFFF); + do { + mod = CInt64_Mod(val, val2); + loopvar3 = CInt64_Add(CInt64_Mul(mod, strideVal), val3); + if (CInt64_Less(loopvar3, loopvar2)) { + loopvar2 = loopvar3; + loopvar1 = val2; + } + if (vectorStride > 1) + break; + val2 = CInt64_Add(val2, cint64_negone); + } while (CInt64_GreaterEqualU(CInt64_Mul(val2, val2), val)); + + *unrollFactor = CInt64_GetULong(&loopvar1); + *leftOver = CInt64_GetULong(&loopvar2); + *needOrigLoop = *leftOver != 0; + *needUnrollBodyTest = CInt64_Less(loopvar1, val) || vectorStride > 1; + *resetUnrolledFinalValue = !(*needOrigLoop && *needUnrollBodyTest); + } + } + + IRO_Dump( + "---- IterCount = %d, VectorStride = %d, UnrollFactor = %d, LeftOver = %d,\n" + "\tNeedOrigLoop = %d, NeedUnrollBodyTest = %d, ResetUnrolledFinalValue = %d\n", + CInt64_GetULong(iterCount), vectorStride, *unrollFactor, *leftOver, + *needOrigLoop, *needUnrollBodyTest, *resetUnrolledFinalValue + ); +} + +IROLinear *BuildOrigIterationCount(IROList *list, IROLoop *loop) { + IROLinear *upperBound; + IROLinear *nd29b; + IROLinear *lowerBound; + IROLinear *finalCount; + IROLinear *divisor; + Type *type; + IROLinear *nd25; + IROLinear *tmp; + Boolean isZeroBase; + Object *tempobj; + IROLinear *iterCount; + IROLinear *negone; + IROLinear *ass; + ENode *expr; + SInt32 powval; + + isZeroBase = 0; + lowerBound = loop->nd14->u.diadic.right; + if (IRO_IsIntConstant(lowerBound) && CInt64_Equal(lowerBound->u.node->data.intval, cint64_zero)) + isZeroBase = 1; + + if (!isZeroBase) + lowerBound = IRO_DuplicateExpr(lowerBound, list); + + if (loop->flags & LoopFlags_1) { + upperBound = IRO_DuplicateExpr(loop->nd18->u.diadic.right, list); + type = loop->nd18->u.diadic.right->rtype; + } else { + upperBound = IRO_DuplicateExpr(loop->nd18->u.diadic.left, list); + type = loop->nd18->u.diadic.left->rtype; + } + + CError_ASSERT(2924, loop->induction); + CError_ASSERT(2929, loop->induction->addConst); + + divisor = IRO_NewLinear(IROLinearOperand); + divisor->index = ++IRO_NumLinear; + divisor->rtype = type; + expr = IRO_NewENode(EINTCONST); + expr->rtype = type; + CInt64_SetLong(&expr->data.intval, loop->induction->addConst); + divisor->u.node = expr; + + if (isZeroBase) { + iterCount = upperBound; + } else { + iterCount = IRO_NewLinear(IROLinearOp2Arg); + iterCount->index = ++IRO_NumLinear; + iterCount->nodetype = ESUB; + iterCount->u.diadic.left = upperBound; + iterCount->u.diadic.right = lowerBound; + iterCount->rtype = type; + IRO_AddToList(iterCount, list); + } + + nd25 = IRO_DuplicateExpr(divisor, list); + + nd29b = IRO_NewLinear(IROLinearOp2Arg); + nd29b->index = ++IRO_NumLinear; + nd29b->nodetype = EADD; + nd29b->u.diadic.left = iterCount; + nd29b->u.diadic.right = nd25; + nd29b->rtype = type; + IRO_AddToList(nd29b, list); + + if (loop->nd18->type == IROLinearOp2Arg && loop->nd18->nodetype == ELESS) { + tmp = nd29b; + + negone = IRO_NewLinear(IROLinearOperand); + negone->index = ++IRO_NumLinear; + negone->rtype = type; + expr = IRO_NewENode(EINTCONST); + expr->rtype = type; + CInt64_SetLong(&expr->data.intval, -1); + negone->u.node = expr; + IRO_AddToList(negone, list); + + nd29b = IRO_NewLinear(IROLinearOp2Arg); + nd29b->index = ++IRO_NumLinear; + nd29b->nodetype = EADD; + nd29b->u.diadic.left = tmp; + nd29b->u.diadic.right = negone; + nd29b->rtype = type; + IRO_AddToList(nd29b, list); + } + + if (CInt64_Equal(divisor->u.node->data.intval, cint64_one)) { + finalCount = nd29b; + } else { + if (divisor->rtype->size <= 4 && IS_TYPE_INT(divisor->rtype) && IRO_IsPow2(divisor, &powval)) { + finalCount = IRO_NewLinear(IROLinearOp2Arg); + finalCount->index = ++IRO_NumLinear; + finalCount->nodetype = ESHL; + finalCount->u.diadic.left = nd29b; + finalCount->u.diadic.right = divisor; + CInt64_SetLong(&divisor->u.node->data.intval, powval); + finalCount->rtype = type; + IRO_AddToList(divisor, list); + IRO_AddToList(finalCount, list); + } else { + finalCount = IRO_NewLinear(IROLinearOp2Arg); + finalCount->index = ++IRO_NumLinear; + finalCount->nodetype = EDIV; + finalCount->u.diadic.left = nd29b; + finalCount->u.diadic.right = divisor; + finalCount->rtype = type; + IRO_AddToList(divisor, list); + IRO_AddToList(finalCount, list); + } + } + + tempobj = create_temp_object(type); + IRO_FindVar(tempobj, 1, 1); + + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->nodetype = EASS; + ass->u.diadic.left = IRO_TempReference(tempobj, list); + ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind; + ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind; + ass->u.diadic.right = finalCount; + ass->u.diadic.right->flags |= IROLF_Reffed; + ass->rtype = type; + IRO_AddToList(ass, list); + + return ass->u.diadic.left; +} + +static IROLinear *BuildOrigIterationCount_DoWhile(IROList *list, IROLoop *loop) { + IROLinear *finalCount; + IROLinear *count; + IROLinear *ass; + Type *type; + Object *tempobj; + ENode *expr; + + type = loop->nd18->u.diadic.left->rtype; + + count = IRO_NewLinear(IROLinearOperand); + count->index = ++IRO_NumLinear; + expr = IRO_NewENode(EINTCONST); + expr->rtype = type; + expr->data.intval = cint64_one; + count->u.node = expr; + count->rtype = type; + IRO_AddToList(count, list); + count->flags |= IROLF_Reffed; + + finalCount = IRO_NewLinear(IROLinearOp2Arg); + finalCount->index = ++IRO_NumLinear; + finalCount->nodetype = EADD; + finalCount->rtype = type; + finalCount->u.diadic.left = IRO_DuplicateExpr(loop->nd18->u.diadic.left, list); + finalCount->u.diadic.left->flags |= IROLF_Reffed; + finalCount->u.diadic.left->flags &= ~IROLF_Assigned; + finalCount->u.diadic.left->u.monadic->flags &= ~IROLF_Assigned; + finalCount->u.diadic.right = count; + IRO_AddToList(finalCount, list); + + tempobj = create_temp_object(type); + IRO_FindVar(tempobj, 1, 1); + + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->nodetype = EASS; + ass->u.diadic.left = IRO_TempReference(tempobj, list); + ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind; + ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind; + ass->u.diadic.right = finalCount; + ass->rtype = type; + IRO_AddToList(ass, list); + + return ass->u.diadic.left; +} + +IROLinear *BuildNewFinalvalue(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop) { + IROLinear *sub; + IROLinear *addvalue; + Type *type; + IROLinear *ass; + IROLinear *dupbound; + Object *tempobj; + ENode *expr; + + type = iterCount->rtype; + + addvalue = IRO_NewLinear(IROLinearOperand); + addvalue->index = ++IRO_NumLinear; + addvalue->rtype = type; + expr = IRO_NewENode(EINTCONST); + expr->rtype = type; + CInt64_SetLong(&expr->data.intval, loop->induction->addConst * unrollFactor); + addvalue->u.node = expr; + IRO_AddToList(addvalue, list); + + if (loop->flags & LoopFlags_1) + dupbound = IRO_DuplicateExpr(loop->nd18->u.diadic.right, list); + else + dupbound = IRO_DuplicateExpr(loop->nd18->u.diadic.left, list); + + sub = IRO_NewLinear(IROLinearOp2Arg); + sub->index = ++IRO_NumLinear; + sub->nodetype = ESUB; + sub->u.diadic.left = dupbound; + sub->u.diadic.right = addvalue; + sub->rtype = type; + IRO_AddToList(sub, list); + + tempobj = create_temp_object(type); + IRO_FindVar(tempobj, 1, 1); + + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->nodetype = EASS; + ass->u.diadic.left = IRO_TempReference(tempobj, list); + ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind; + ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind; + ass->u.diadic.right = sub; + ass->u.diadic.right->flags |= IROLF_Reffed; + ass->rtype = type; + IRO_AddToList(ass, list); + + return ass->u.diadic.left; +} + +static IROLinear *BuildPreAlignTemp(IROLoopInd *ind, UInt32 unrollFactor, IROList *list) { + Type *type; + IROLinear *indnd; + IROLinear *factornd; + IROLinear *div; + IROLinear *constnd; + IROLinear *add; + IROLinear *mul; + IROLinear *ass; + Object *tempobj; + ENode *expr; + + indnd = ind->nd; + type = indnd->rtype; + + factornd = IRO_NewLinear(IROLinearOperand); + factornd->index = ++IRO_NumLinear; + factornd->rtype = type; + expr = IRO_NewENode(EINTCONST); + expr->rtype = type; + CInt64_SetLong(&expr->data.intval, unrollFactor); + factornd->u.node = expr; + IRO_AddToList(factornd, list); + + if (indnd->type == IROLinearOp1Arg) + IRO_DuplicateExpr(indnd->u.monadic, list); + else + IRO_DuplicateExpr(indnd->u.diadic.left, list); + + list->tail->flags &= ~IROLF_Assigned; + list->tail->u.monadic->flags &= ~IROLF_Assigned; + + div = IRO_NewLinear(IROLinearOp2Arg); + div->index = ++IRO_NumLinear; + div->nodetype = EDIV; + div->u.diadic.left = list->tail; + div->u.diadic.right = factornd; + div->rtype = type; + IRO_AddToList(div, list); + div->flags |= IROLF_Reffed; + + constnd = IRO_NewLinear(IROLinearOperand); + constnd->index = ++IRO_NumLinear; + expr = IRO_NewENode(EINTCONST); + expr->rtype = type; + expr->data.intval = cint64_one; + constnd->u.node = expr; + constnd->rtype = type; + IRO_AddToList(constnd, list); + constnd->flags |= IROLF_Reffed; + + add = IRO_NewLinear(IROLinearOp2Arg); + add->index = ++IRO_NumLinear; + add->nodetype = EADD; + add->u.diadic.left = div; + add->u.diadic.right = constnd; + add->rtype = type; + IRO_AddToList(add, list); + add->flags |= IROLF_Reffed; + + IRO_DuplicateExpr(factornd, list); + + mul = IRO_NewLinear(IROLinearOp2Arg); + mul->index = ++IRO_NumLinear; + mul->nodetype = EMUL; + mul->u.diadic.left = add; + mul->u.diadic.right = list->tail; + mul->rtype = type; + IRO_AddToList(mul, list); + mul->flags |= IROLF_Reffed; + + tempobj = create_temp_object(type); + IRO_FindVar(tempobj, 1, 1); + + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->nodetype = EASS; + ass->u.diadic.left = IRO_TempReference(tempobj, list); + ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind; + ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind; + ass->u.diadic.right = mul; + ass->u.diadic.right->flags |= IROLF_Reffed; + ass->rtype = type; + IRO_AddToList(ass, list); + + return ass->u.diadic.left; +} + +static IROLinear *BuildNewFinalvalue_DoWhile(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop) { + IROLinear *addvalue; + IROLinear *add; + IROLinear *mul; + IROLinear *ass; + Type *type; + Object *tempobj; + ENode *expr; + + type = iterCount->rtype; + + addvalue = IRO_NewLinear(IROLinearOperand); + addvalue->index = ++IRO_NumLinear; + addvalue->rtype = type; + expr = IRO_NewENode(EINTCONST); + expr->rtype = type; + CInt64_SetLong(&expr->data.intval, loop->induction->addConst); + addvalue->u.node = expr; + IRO_AddToList(addvalue, list); + addvalue->flags |= IROLF_Reffed; + + mul = IRO_NewLinear(IROLinearOp2Arg); + mul->index = ++IRO_NumLinear; + mul->nodetype = EMUL; + mul->u.diadic.left = IRO_DuplicateExpr(iterCount, list); + mul->u.diadic.right = addvalue; + mul->rtype = type; + IRO_AddToList(mul, list); + mul->flags |= IROLF_Reffed; + mul->u.diadic.left->flags &= ~IROLF_Assigned; + mul->u.diadic.left->u.diadic.left->flags &= ~IROLF_Assigned; + + if (loop->induction->nd->type == IROLinearOp1Arg) + IRO_DuplicateExpr(loop->induction->nd->u.monadic, list); + else + IRO_DuplicateExpr(loop->induction->nd->u.diadic.left, list); + list->tail->flags &= ~IROLF_Assigned; + list->tail->u.diadic.left->flags &= ~IROLF_Assigned; + + add = IRO_NewLinear(IROLinearOp2Arg); + add->index = ++IRO_NumLinear; + add->nodetype = EADD; + add->u.diadic.left = mul; + add->u.diadic.right = list->tail; + add->rtype = type; + IRO_AddToList(add, list); + add->flags |= IROLF_Reffed; + + tempobj = create_temp_object(type); + IRO_FindVar(tempobj, 1, 1); + + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->nodetype = EASS; + ass->u.diadic.left = IRO_TempReference(tempobj, list); + ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind; + ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind; + ass->u.diadic.right = add; + ass->u.diadic.right->flags |= IROLF_Reffed; + ass->rtype = type; + IRO_AddToList(ass, list); + + return ass->u.diadic.left; +} + +static IROLinear *BuildUnrolledFinalvalue_DoWhile(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop) { + IROLinear *addvalue_mult; + IROLinear *addvalue; + IROLinear *mul; + IROLinear *sub; + IROLinear *add; + IROLinear *ass; + Type *type; + Object *tempobj; + ENode *expr; + + type = iterCount->rtype; + + addvalue_mult = IRO_NewLinear(IROLinearOperand); + addvalue_mult->index = ++IRO_NumLinear; + addvalue_mult->rtype = type; + expr = IRO_NewENode(EINTCONST); + expr->rtype = type; + CInt64_SetLong(&expr->data.intval, loop->induction->addConst * unrollFactor); + addvalue_mult->u.node = expr; + IRO_AddToList(addvalue_mult, list); + addvalue_mult->flags |= IROLF_Reffed; + + addvalue = IRO_NewLinear(IROLinearOperand); + addvalue->index = ++IRO_NumLinear; + addvalue->rtype = type; + expr = IRO_NewENode(EINTCONST); + expr->rtype = type; + CInt64_SetLong(&expr->data.intval, loop->induction->addConst); + addvalue->u.node = expr; + IRO_AddToList(addvalue, list); + addvalue->flags |= IROLF_Reffed; + + mul = IRO_NewLinear(IROLinearOp2Arg); + mul->index = ++IRO_NumLinear; + mul->nodetype = EMUL; + mul->u.diadic.left = IRO_DuplicateExpr(iterCount, list); + mul->u.diadic.right = addvalue; + mul->rtype = type; + IRO_AddToList(mul, list); + mul->flags |= IROLF_Reffed; + mul->u.diadic.left->flags &= ~IROLF_Assigned; + mul->u.diadic.left->u.diadic.left->flags &= ~IROLF_Assigned; + + sub = IRO_NewLinear(IROLinearOp2Arg); + sub->index = ++IRO_NumLinear; + sub->nodetype = ESUB; + sub->u.diadic.left = mul; + sub->u.diadic.right = addvalue_mult; + sub->rtype = type; + IRO_AddToList(sub, list); + sub->flags |= IROLF_Reffed; + + if (loop->induction->nd->type == IROLinearOp1Arg) + IRO_DuplicateExpr(loop->induction->nd->u.monadic, list); + else + IRO_DuplicateExpr(loop->induction->nd->u.diadic.left, list); + list->tail->flags &= ~IROLF_Assigned; + list->tail->u.diadic.left->flags &= ~IROLF_Assigned; + + add = IRO_NewLinear(IROLinearOp2Arg); + add->index = ++IRO_NumLinear; + add->nodetype = EADD; + add->u.diadic.left = sub; + add->u.diadic.right = list->tail; + add->rtype = type; + IRO_AddToList(add, list); + add->flags |= IROLF_Reffed; + + tempobj = create_temp_object(type); + IRO_FindVar(tempobj, 1, 1); + + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->nodetype = EASS; + ass->u.diadic.left = IRO_TempReference(tempobj, list); + ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind; + ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind; + ass->u.diadic.right = add; + ass->u.diadic.right->flags |= IROLF_Reffed; + ass->rtype = type; + IRO_AddToList(ass, list); + + return ass->u.diadic.left; +} + +void BuildUnrolledBodyEntryTest(IROList *list, IROLinear *iterCount, UInt32 unrollFactor, CLabel *label) { + Type *type; + IROLinear *ifnot; + IROLinear *comp; + IROLinear *var; + IROLinear *value; + ENode *expr; + + type = iterCount->rtype; + + value = IRO_NewLinear(IROLinearOperand); + value->index = ++IRO_NumLinear; + value->rtype = type; + expr = IRO_NewENode(EINTCONST); + expr->rtype = type; + CInt64_SetLong(&expr->data.intval, unrollFactor); + value->u.node = expr; + IRO_AddToList(value, list); + + var = IRO_DuplicateExpr(iterCount, list); + + comp = IRO_NewLinear(IROLinearOp2Arg); + comp->index = ++IRO_NumLinear; + comp->nodetype = EGREATER; + comp->u.diadic.left = var; + comp->u.diadic.right = value; + comp->u.diadic.right->flags |= IROLF_Reffed; + comp->rtype = type; + IRO_AddToList(comp, list); + + ifnot = IRO_NewLinear(IROLinearOp1Arg); + ifnot->index = ++IRO_NumLinear; + ifnot->type = IROLinearIfNot; + ifnot->u.label.x4 = comp; + ifnot->u.label.x4->flags |= IROLF_Reffed; + ifnot->rtype = type; + ifnot->u.label.label = label; + IRO_AddToList(ifnot, list); +} + +void ChangeInductionReference(IROLinear *first, IROLinear *last, CInt64 val, IROLoop *loop) { + IROLinear *nd; + IROLinear *value; + IROLinear *add; + UInt32 isUnsigned; + IROLinear *father; + Boolean flag; + IROLinear *father2; + IROLinear *father3; + Type *tmp; + UInt32 flag2; + Object *varobj; + IROLinear *next; + ENode *expr; + Type *type; + + CInt64 val2; + CInt64 val1; + IROList list; + + type = loop->induction->nd->rtype; + isUnsigned = IRO_IsUnsignedType(type); + + for (nd = first; nd; nd = next) { + next = nd->next; + + varobj = IRO_IsVariable(nd); + if (varobj && loop->induction->var->object == varobj) { + value = IRO_NewLinear(IROLinearOperand); + value->index = ++IRO_NumLinear; + value->rtype = type; + expr = IRO_NewENode(EINTCONST); + expr->rtype = type; + expr->data.intval = val; + value->u.node = expr; + + add = IRO_NewLinear(IROLinearOp2Arg); + add->index = ++IRO_NumLinear; + add->nodetype = EADD; + add->rtype = type; + + father = IRO_LocateFather(nd); + flag = 1; + if (father && IS_LINEAR_MONADIC(father, ETYPCON)) { + tmp = father->rtype; + father = IRO_LocateFather(father); + if (tmp->type != nd->rtype->type || tmp->size < nd->rtype->size) + flag = 0; + } + + flag2 = 0; + if ( + flag && + father && + IS_LINEAR_DIADIC_2(father, ESHL, EMUL) && + IRO_IsIntConstant(father->u.diadic.right) && + (father2 = IRO_LocateFather(father)) && + IS_LINEAR_DIADIC(father2, EADD) && + father2->u.diadic.right == father && + (father3 = IRO_LocateFather(father2)) + ) + { + IRO_InitList(&list); + val2 = father->u.diadic.right->u.node->data.intval; + if (father->nodetype == ESHL) + val2 = CInt64_Shl(cint64_one, val2); + + val1 = value->u.node->data.intval; + if (isUnsigned) + val1 = CInt64_MulU(val2, val1); + else + val1 = CInt64_Mul(val2, val1); + value->u.node->data.intval = val1; + + IRO_AddToList(value, &list); + IRO_AddToList(add, &list); + add->u.diadic.right = value; + IRO_Paste(list.head, list.tail, father3); + IRO_LocateFather_Cut_And_Paste_Without_Nopping(father2, add); + add->u.diadic.left = father2; + add->rtype = father2->rtype; + flag2 = 1; + } + + if (!flag2) { + add->u.diadic.right = value; + add->u.diadic.right->flags |= IROLF_Reffed; + value->next = add; + + add->u.diadic.left = nd; + IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, add); + add->flags |= IROLF_Reffed; + + nd->next = value; + add->next = next; + } + } + + if (nd == last) + break; + } +} + +IROLinear *UpdateInductionIncrement(IROLoop *loop, SInt32 value, IROLinear *before) { + IROLinear *ind_nd; + IROLinear *addvalue; + IROLinear *ass; + Type *type; + ENode *expr; + IROList list; + + IRO_InitList(&list); + ind_nd = loop->induction->nd; + type = ind_nd->rtype; + + addvalue = IRO_NewLinear(IROLinearOperand); + addvalue->index = ++IRO_NumLinear; + addvalue->rtype = type; + expr = IRO_NewENode(EINTCONST); + expr->rtype = type; + CInt64_SetLong(&expr->data.intval, value * loop->induction->addConst); + addvalue->u.node = expr; + IRO_AddToList(addvalue, &list); + + if (IS_LINEAR_MONADIC_2(ind_nd, EPREINC, EPOSTINC)) { + ind_nd = IRO_DuplicateExpr(ind_nd->u.monadic, &list); + + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->nodetype = EADDASS; + ass->u.diadic.left = ind_nd; + ass->u.diadic.right = addvalue; + ass->rtype = type; + IRO_AddToList(ass, &list); + } else if (IS_LINEAR_MONADIC_2(ind_nd, EPREDEC, EPOSTDEC)) { + ind_nd = IRO_DuplicateExpr(ind_nd->u.monadic, &list); + + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->nodetype = ESUBASS; + ass->u.diadic.left = ind_nd; + ass->u.diadic.right = addvalue; + ass->rtype = type; + IRO_AddToList(ass, &list); + } else if (IS_LINEAR_DIADIC(ind_nd, EADDASS)) { + ind_nd = IRO_DuplicateExpr(ind_nd->u.monadic, &list); + + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->index = ++IRO_NumLinear; + ass->nodetype = EADDASS; + ass->u.diadic.left = ind_nd; + ass->u.diadic.right = addvalue; + ass->rtype = type; + IRO_AddToList(ass, &list); + } + + IRO_Paste(list.head, list.tail, before); + return list.tail; +} + +void GenInitialAssignment(IROLoop *loop, Object *var, IROList *list) { + Type *type; + IROLinear *nd; + + CError_ASSERT(3924, loop->nd14 && loop->nd14->type == IROLinearOp2Arg); + + type = loop->induction->nd->rtype; + + nd = IRO_NewLinear(IROLinearOp2Arg); + nd->index = ++IRO_NumLinear; + nd->nodetype = EASS; + nd->u.diadic.left = IRO_TempReference(var, list); + nd->u.diadic.right = IRO_DuplicateExpr(loop->nd14->u.diadic.right, list); + nd->rtype = type; + IRO_AddToList(nd, list); +} + +void GenNewInduction(void) { + CError_FATAL(3941); +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.h b/compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.h new file mode 100644 index 0000000..fd4972b --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.h @@ -0,0 +1,23 @@ +#ifndef COMPILER_IROUNROLLLOOP_H +#define COMPILER_IROUNROLLLOOP_H + +#include "IrOptimizer.h" +#include "IroLinearForm.h" + +extern void IRO_LoopUnroller(void); +extern void IRO_IterateForLoopBody(IRONode *start, IRONode *end, IROLoop *loop, IROLinear *destnode, SInt32 addConst, CInt64 *val, Boolean funkyFlag); +extern void IRO_LinearizeForLoopPostLoop(IRONode *fnode1, IRONode *fnode2, IROLoop *loop, IRONode *fnode3, UInt32 unrollFactor); +extern IROLinear *BuildEarlyLoopExitTest(IROLinearType type, IROList *list); +extern IROLinear *BuildLoopExitTest(IROLinearType type, IROList *list); +extern int IsIterationCountConstant(IROLoop *loop, CInt64 *pval); +extern void NoOpBlock(IRONode *fnode); +extern void IRO_TestConstantIterationCount(IROLoop *loop, CInt64 *iterCount, SInt32 vectorStride, UInt32 *unrollFactor, SInt32 *leftOver, UInt32 *needOrigLoop, UInt32 *needUnrollBodyTest, UInt32 *resetUnrolledFinalValue); +extern IROLinear *BuildOrigIterationCount(IROList *list, IROLoop *loop); +extern IROLinear *BuildNewFinalvalue(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop); +extern void BuildUnrolledBodyEntryTest(IROList *list, IROLinear *iterCount, UInt32 unrollFactor, CLabel *label); +extern void ChangeInductionReference(IROLinear *first, IROLinear *last, CInt64 val, IROLoop *loop); +extern IROLinear *UpdateInductionIncrement(IROLoop *loop, SInt32 value, IROLinear *before); +extern void GenInitialAssignment(IROLoop *loop, Object *var, IROList *list); +extern void GenNewInduction(void); + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroUtil.c b/compiler_and_linker/FrontEnd/Optimizer/IroUtil.c new file mode 100644 index 0000000..7e6321d --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroUtil.c @@ -0,0 +1,1262 @@ +#include "IroUtil.h" +#include "IroCSE.h" +#include "IroDump.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroLoop.h" +#include "IroVars.h" +#include "compiler/InlineAsmPPC.h" +#include "compiler/CompilerTools.h" +#include "compiler/CCompiler.h" +#include "compiler/CError.h" +#include "compiler/CException.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/Exceptions.h" +#include "compiler/objects.h" +#include "compiler/types.h" +#include "cos.h" + +static UInt32 IRO_LastUserBreakTick; +static IROLinear *ExprStart; +static IROLinear *ExprEnd; +static IRONode *IRO_Node; +static SInt32 FuncLevel; +Object *FunctionName; +Boolean IRO_IsLeafFunction; +Boolean IRO_FunctionHasReturn; +Boolean DisableDueToAsm; +Boolean LoopOptimizerRun; + +Object *IRO_IsVariable(IROLinear *linear) { + if (linear->type == IROLinearOp1Arg && + linear->nodetype == EINDIRECT && + linear->u.monadic->type == IROLinearOperand && + linear->u.monadic->u.node->type == EOBJREF) + return linear->u.monadic->u.node->data.objref; + + return NULL; +} + +Boolean IRO_IsConstant(IROLinear *linear) { + if (linear->type == IROLinearOperand && ENODE_IS3(linear->u.node, EINTCONST, EVECTOR128CONST, EFLOATCONST)) + return 1; + return 0; +} + +Boolean IRO_IsPow2(IROLinear *linear, SInt32 *powvalue) { + UInt32 desired; + UInt32 value; + SInt32 i; + + *powvalue = -1; + if (linear->type == IROLinearOperand && linear->u.node->type == EINTCONST) { + if (CTool_EndianReadWord32(&linear->u.node->data.intval.hi)) + return 0; + + desired = CInt64_GetULong(&linear->u.node->data.intval); + value = 1; + for (i = 0; i < 31; i++) { + if (value == desired) { + *powvalue = i; + return 1; + } + value += value; + } + } + + return 0; +} + +Boolean IRO_IsIntConstant(IROLinear *linear) { + if (linear->type == IROLinearOperand && ENODE_IS(linear->u.node, EINTCONST)) + return 1; + return 0; +} + +Boolean IRO_IsFloatConstant(IROLinear *linear) { + if (linear->type == IROLinearOperand && ENODE_IS(linear->u.node, EFLOATCONST)) + return 1; + return 0; +} + +Boolean IRO_IsVector128Constant(IROLinear *linear) { + if (linear->type == IROLinearOperand && ENODE_IS(linear->u.node, EVECTOR128CONST)) + return 1; + return 0; +} + +Boolean IRO_IsAssignment(IROLinear *linear) { + if (linear->type == IROLinearOp1Arg || linear->type == IROLinearOp2Arg) { + if (IRO_IsAssignOp[linear->nodetype]) + return 1; + } + return 0; +} + +static Boolean IRO_OperandsSame(ENode *a, ENode *b) { + if (a->type == b->type) { + switch (a->type) { + case EINTCONST: + return CInt64_Equal(a->data.intval, b->data.intval); + case ESTRINGCONST: + return 0; + case EFLOATCONST: + return a->data.floatval.value == b->data.floatval.value; + case EVECTOR128CONST: + return (a->data.vector128val.ul[0] == b->data.vector128val.ul[0]) && + (a->data.vector128val.ul[1] == b->data.vector128val.ul[1]) && + (a->data.vector128val.ul[2] == b->data.vector128val.ul[2]) && + (a->data.vector128val.ul[3] == b->data.vector128val.ul[3]); + case EOBJREF: + return a->data.objref == b->data.objref; + } + } + + return 0; +} + +Boolean IRO_TypesEqual(Type *a, Type *b) { + if (IS_TYPE_BITFIELD(a)) { + if (IS_TYPE_BITFIELD(b)) { + if ( + (TYPE_BITFIELD(a)->bitfieldtype == TYPE_BITFIELD(b)->bitfieldtype) && + (TYPE_BITFIELD(a)->offset == TYPE_BITFIELD(b)->offset) && + (TYPE_BITFIELD(a)->bitlength == TYPE_BITFIELD(b)->bitlength)) + return 1; + } + return 0; + } + + if (IS_TYPE_POINTER_ONLY(a) && IS_TYPE_POINTER_ONLY(b)) + return 1; + + return is_typeequal(a, b) != 0; +} + +Type *IRO_UnsignedType(Type *type) { + if (IS_TYPE_ENUM(type) || IS_TYPE_POINTER_ONLY(type)) { + if (type->size == stunsignedchar.size) + return TYPE(&stunsignedchar); + if (type->size == stunsignedint.size) + return TYPE(&stunsignedint); + if (type->size == stunsignedshort.size) + return TYPE(&stunsignedshort); + if (type->size == stunsignedlong.size) + return TYPE(&stunsignedlong); + if (type->size == stunsignedlonglong.size) + return TYPE(&stunsignedlonglong); + CError_FATAL(281); + return NULL; + } + + if (!IS_TYPE_INT(type)) { + CError_FATAL(287); + return NULL; + } + + if (type == TYPE(&stbool) || type == TYPE(&stwchar)) + return type; + + if (type == TYPE(&stchar) || type == TYPE(&stsignedchar) || type == TYPE(&stunsignedchar)) + return TYPE(&stunsignedchar); + if (type == TYPE(&stsignedshort) || type == TYPE(&stunsignedshort)) + return TYPE(&stunsignedshort); + if (type == TYPE(&stsignedint) || type == TYPE(&stunsignedint)) + return TYPE(&stunsignedint); + if (type == TYPE(&stsignedlong) || type == TYPE(&stunsignedlong)) + return TYPE(&stunsignedlong); + if (type == TYPE(&stsignedlonglong) || type == TYPE(&stunsignedlonglong)) + return TYPE(&stunsignedlonglong); + + CError_FATAL(319); + return NULL; +} + +Type *IRO_SignedType(Type *type) { + if (IS_TYPE_ENUM(type) || IS_TYPE_POINTER_ONLY(type)) { + if (type->size == stsignedchar.size) + return TYPE(&stsignedchar); + if (type->size == stsignedint.size) + return TYPE(&stsignedint); + if (type->size == stsignedshort.size) + return TYPE(&stsignedshort); + if (type->size == stsignedlong.size) + return TYPE(&stsignedlong); + if (type->size == stsignedlonglong.size) + return TYPE(&stsignedlonglong); + CError_FATAL(357); + return NULL; + } + + if (!IS_TYPE_INT(type)) { + CError_FATAL(363); + return NULL; + } + + if (type == TYPE(&stbool) && type->size == stsignedchar.size) + return TYPE(&stsignedchar); + + if (type == TYPE(&stwchar) && type->size == stsignedshort.size) + return TYPE(&stsignedshort); + + if (type == TYPE(&stchar) || type == TYPE(&stsignedchar) || type == TYPE(&stunsignedchar)) + return TYPE(&stsignedchar); + if (type == TYPE(&stsignedshort) || type == TYPE(&stunsignedshort)) + return TYPE(&stsignedshort); + if (type == TYPE(&stsignedint) || type == TYPE(&stunsignedint)) + return TYPE(&stsignedint); + if (type == TYPE(&stsignedlong) || type == TYPE(&stunsignedlong)) + return TYPE(&stsignedlong); + if (type == TYPE(&stsignedlonglong) || type == TYPE(&stunsignedlonglong)) + return TYPE(&stsignedlonglong); + + CError_FATAL(399); + return NULL; +} + +Boolean IRO_is_CPtypeequal(Type *a, Type *b) { + if (IS_TYPE_POINTER_ONLY(a) && IS_TYPE_POINTER_ONLY(b)) + return 1; + + return is_typeequal(a, b) != 0; +} + +Boolean IRO_ExprsSame(IROLinear *a, IROLinear *b) { + if (a->type == b->type && IRO_TypesEqual(a->rtype, b->rtype)) { + switch (a->type) { + case IROLinearOperand: + return IRO_OperandsSame(a->u.node, b->u.node); + case IROLinearOp1Arg: + if (a->nodetype == b->nodetype) + return IRO_ExprsSame(a->u.monadic, b->u.monadic); + return 0; + case IROLinearOp2Arg: + if (a->nodetype == b->nodetype) + return IRO_ExprsSame(a->u.diadic.left, b->u.diadic.left) && + IRO_ExprsSame(a->u.diadic.right, b->u.diadic.right); + return 0; + case IROLinearOp3Arg: + if (a->nodetype == b->nodetype) + return IRO_ExprsSame(a->u.args3.a, b->u.args3.a) && + IRO_ExprsSame(a->u.args3.b, b->u.args3.b) && + IRO_ExprsSame(a->u.args3.c, b->u.args3.c); + return 0; + case IROLinearFunccall: + return 0; + default: + return 0; + } + } + + return 0; +} + +CLabel *IRO_NewLabel(void) { + CLabel *label = newlabel(); + label->next = Labels; + Labels = label; + return label; +} + +Boolean IRO_ExprsSameSemantically(IROLinear *a, IROLinear *b) { + if (a->type == b->type && IRO_TypesEqual(a->rtype, b->rtype)) { + Boolean flag = 0; + + switch (a->type) { + case IROLinearOperand: + return IRO_OperandsSame(a->u.node, b->u.node); + case IROLinearOp1Arg: + if (a->nodetype == b->nodetype) + return IRO_ExprsSameSemantically(a->u.monadic, b->u.monadic); + return 0; + case IROLinearOp2Arg: + if (a->nodetype == b->nodetype) { + switch (a->nodetype) { + case EMUL: + case EADD: + case EAND: + case EXOR: + case EOR: + case ELAND: + case ELOR: + if (!IRO_HasSideEffect(a)) { + flag = IRO_ExprsSameSemantically(a->u.diadic.left, b->u.diadic.right) && + IRO_ExprsSameSemantically(a->u.diadic.right, b->u.diadic.left); + } + } + + return flag || (IRO_ExprsSameSemantically(a->u.diadic.left, b->u.diadic.left) && + IRO_ExprsSameSemantically(a->u.diadic.right, b->u.diadic.right)); + } + return 0; + case IROLinearOp3Arg: + if (a->nodetype == b->nodetype) + return IRO_ExprsSameSemantically(a->u.args3.a, b->u.args3.a) && + IRO_ExprsSameSemantically(a->u.args3.b, b->u.args3.b) && + IRO_ExprsSameSemantically(a->u.args3.c, b->u.args3.c); + return 0; + case IROLinearFunccall: + return 0; + default: + return 0; + } + } + + return 0; +} + +IROLinear *IRO_FindPrecedAfter(IROLinear *a, IROLinear *iter) { + IROLinear *prev = iter; + while (iter && iter != a) { + prev = iter; + iter = iter->next; + } + + if (iter) + return prev; + return iter; +} + +IROLinear *IRO_FindPreced(IROLinear *a) { + IROLinear *iter; + IROLinear *prev; + + prev = iter = IRO_FirstLinear; + while (iter && iter != a) { + prev = iter; + iter = iter->next; + } + + if (iter) + return prev; + return iter; +} + +IROLinear *IRO_FindFirst(IROLinear *linear) { + short i; + + switch (linear->type) { + case IROLinearOperand: + return linear; + case IROLinearOp1Arg: + return IRO_FindFirst(linear->u.monadic); + case IROLinearOp2Arg: + if (linear->u.diadic.right->index < linear->u.diadic.left->index) + return IRO_FindFirst(linear->u.diadic.right); + else + return IRO_FindFirst(linear->u.diadic.left); + case IROLinearOp3Arg: + if (linear->u.args3.a->index < linear->u.args3.b->index) { + if (linear->u.args3.b->index < linear->u.args3.c->index) + return IRO_FindFirst(linear->u.args3.a); + else + return IRO_FindFirst(linear->u.args3.c); + } else { + if (linear->u.args3.b->index < linear->u.args3.c->index) + return IRO_FindFirst(linear->u.args3.b); + else + return IRO_FindFirst(linear->u.args3.c); + } + case IROLinearFunccall: + i = linear->u.funccall.argCount - 1; + return IRO_FindFirst(linear->u.funccall.args[i]); + default: + CError_FATAL(641); + return NULL; + } +} + +void IRO_CutAndPasteAfter(IROLinear *a, IROLinear *b, IROLinear *c) { + IROLinear *preced = IRO_FindPreced(a); + preced->next = b->next; + b->next = c->next; + c->next = a; +} + +Boolean IRO_IsConstantZero(IROLinear *linear) { + return (IRO_IsIntConstant(linear) && CInt64_IsZero(&linear->u.node->data.intval)) || + (IRO_IsFloatConstant(linear) && CMach_FloatIsZero(linear->u.node->data.floatval)); +} + +Boolean IRO_IsConstantOne(IROLinear *linear) { + return (IRO_IsIntConstant(linear) && CInt64_IsOne(&linear->u.node->data.intval)) || + (IRO_IsFloatConstant(linear) && CMach_FloatIsOne(linear->u.node->data.floatval)); +} + +Boolean IRO_IsConstantNegativeOne(IROLinear *linear) { + CInt64 neg = CInt64_Neg(linear->u.node->data.intval); + return (IRO_IsIntConstant(linear) && CInt64_IsOne(&neg)) || + (IRO_IsFloatConstant(linear) && CMach_FloatIsNegOne(linear->u.node->data.floatval)); +} + +static void ActNop(IROLinear *linear, Boolean isEntry) { + if (!isEntry) { + linear->type = IROLinearNop; + linear->expr = NULL; + } +} + +void IRO_NopOut(IROLinear *linear) { + IRO_WalkTree(linear, ActNop); +} + +static Boolean NotNoppable(IROLinear *linear) { + return ( + (linear->type == IROLinearFunccall) || + IRO_IsAssignment(linear) || + ((linear->type == IROLinearOperand) && ENODE_IS(linear->u.node, EINSTRUCTION)) || + (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) || + ((linear->type == IROLinearOperand) && ENODE_IS(linear->u.node, EOBJREF) && is_volatile_object(linear->u.node->data.objref)) + ); +} + +static void ActNopNonSideEffects(IROLinear *linear, Boolean isEntry) { + if (isEntry) { + if (NotNoppable(linear)) { + if (!FuncLevel) + linear->flags &= ~IROLF_Reffed; + FuncLevel++; + } + } else { + if (NotNoppable(linear)) { + FuncLevel--; + } else if (!FuncLevel) { + linear->type = IROLinearNop; + } + } +} + +void IRO_NopNonSideEffects(IROLinear *linear, SInt32 level) { + FuncLevel = level; + IRO_WalkTree(linear, ActNopNonSideEffects); +} + +void IRO_BuildList(IROLinear *linear, Boolean isEntry) { + if (!isEntry) { + linear->next = NULL; + IRO_AddToList(linear, &IRO_InitLList); + } +} + +void IRO_WalkTree(IROLinear *linear, IROWalkTreeFunc func) { + int i; + + func(linear, 1); + switch (linear->type) { + case IROLinearOperand: + break; + case IROLinearOp1Arg: + IRO_WalkTree(linear->u.monadic, func); + break; + case IROLinearOp2Arg: + IRO_WalkTree(linear->u.diadic.left, func); + IRO_WalkTree(linear->u.diadic.right, func); + break; + case IROLinearOp3Arg: + IRO_WalkTree(linear->u.args3.a, func); + IRO_WalkTree(linear->u.args3.b, func); + IRO_WalkTree(linear->u.args3.c, func); + break; + case IROLinearFunccall: + IRO_WalkTree(linear->u.funccall.linear8, func); + for (i = 0; i < linear->u.funccall.argCount; i++) + IRO_WalkTree(linear->u.funccall.args[i], func); + break; + } + func(linear, 0); +} + +void IRO_WalkTreeToPropagateFlags(IROLinear *linear, IROWalkTreeFunc func) { + int i; + + switch (linear->type) { + case IROLinearOperand: + break; + case IROLinearOp1Arg: + IRO_WalkTreeToPropagateFlags(linear->u.monadic, func); + break; + case IROLinearOp2Arg: + IRO_WalkTreeToPropagateFlags(linear->u.diadic.left, func); + IRO_WalkTreeToPropagateFlags(linear->u.diadic.right, func); + break; + case IROLinearOp3Arg: + IRO_WalkTreeToPropagateFlags(linear->u.args3.a, func); + IRO_WalkTreeToPropagateFlags(linear->u.args3.b, func); + IRO_WalkTreeToPropagateFlags(linear->u.args3.c, func); + break; + case IROLinearFunccall: + IRO_WalkTreeToPropagateFlags(linear->u.funccall.linear8, func); + for (i = 0; i < linear->u.funccall.argCount; i++) + IRO_WalkTreeToPropagateFlags(linear->u.funccall.args[i], func); + break; + } + func(linear, 0); +} + +void IRO_WalkInts(IROLinear *a, IROLinear *b, IROWalkTreeFunc func) { + IROLinear *scan; + + for (scan = a; scan; scan = scan->next) { + switch (scan->type) { + case IROLinearBeginCatch: + case IROLinearEndCatch: + case IROLinearEndCatchDtor: + IRO_WalkTree(scan->u.ctch.linear, func); + break; + case IROLinearOperand: + case IROLinearOp1Arg: + case IROLinearOp2Arg: + case IROLinearOp3Arg: + case IROLinearFunccall: + IRO_WalkTree(scan, func); + break; + case IROLinearIf: + case IROLinearIfNot: + IRO_WalkTree(scan->u.label.x4, func); + break; + case IROLinearReturn: + if (scan->u.monadic) + IRO_WalkTree(scan->u.monadic, func); + break; + case IROLinearSwitch: + IRO_WalkTree(scan->u.swtch.x4, func); + break; + case IROLinearAsm: + func(scan, 1); + func(scan, 0); + break; + case IROLinearEnd: + break; + } + + if (scan == b) + break; + } +} + +void IRO_Cut(IROLinear *a, IROLinear *b) { + IROLinear *scan; + IROLinear *prev; + IRONode *node; + + scan = a; + while (1) { + scan->stmt = NULL; + if (scan == b) + break; + scan = scan->next; + } + + prev = NULL; + for (scan = IRO_FirstLinear; scan && scan != a; scan = scan->next) + prev = scan; + + CError_ASSERT(951, scan); + + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (node->first == a) { + if (node->last == b) { + node->first = node->last = NULL; + break; + } else { + node->first = b->next; + break; + } + } else if (node->last == b) { + node->last = prev; + break; + } + } + + if (prev) + prev->next = b->next; + else + IRO_FirstLinear = b->next; +} + +void IRO_Paste(IROLinear *a, IROLinear *b, IROLinear *c) { + IROLinear *prev; + IROLinear *scan; + IRONode *node; + + CError_ASSERT(1002, c && c->type != IROLinearLabel); + + prev = NULL; + for (scan = IRO_FirstLinear; scan && scan != c; scan = scan->next) + prev = scan; + + CError_ASSERT(1016, scan); + + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (node->first == c) { + node->first = a; + break; + } + } + + b->next = c; + if (prev) + prev->next = a; + else + IRO_FirstLinear = a; +} + +void IRO_PasteAfter(IROLinear *a, IROLinear *b, IROLinear *c) { + IRONode *node; + + switch (c->type) { + case IROLinearGoto: + case IROLinearIf: + case IROLinearIfNot: + case IROLinearSwitch: + CError_FATAL(1060); + } + + for (node = IRO_FirstNode; node; node = node->nextnode) { + if (node->last == c) { + node->last = b; + break; + } + } + + b->next = c->next; + c->next = a; +} + +static void FindStart(IROLinear *linear, Boolean isEntry) { + IROLinear *scan; + if (isEntry) { + scan = linear; + do { + if (scan == ExprStart) { + ExprStart = linear; + return; + } + if (scan == ExprEnd) + return; + } while ((scan = scan->next)); + } +} + +void IRO_ClipExpr(IROExpr *expr) { + ExprStart = ExprEnd = expr->linear; + IRO_WalkTree(expr->linear, FindStart); + IRO_Cut(ExprStart, ExprEnd); +} + +void IRO_ClipExprTree(IROLinear *linear) { + ExprStart = ExprEnd = linear; + IRO_WalkTree(linear, FindStart); + IRO_Cut(ExprStart, ExprEnd); +} + +static void SetNodeNumInExprList(IROLinear *linear, Boolean isEntry) { + if (isEntry && linear->expr) + linear->expr->node = IRO_Node; +} + +void IRO_MoveExpression(IROExpr *expr, IROLinear *linear) { + IRONode *node; + IROLinear *scan; + + ExprStart = ExprEnd = expr->linear; + IRO_WalkTree(expr->linear, FindStart); + + if (ExprStart != linear) { + IRO_Cut(ExprStart, ExprEnd); + IRO_Paste(ExprStart, ExprEnd, linear); + for (node = IRO_FirstNode; node; node = node->nextnode) { + for (scan = node->first; scan; scan = scan->next) { + if (scan == expr->linear) { + expr->node = node; + break; + } + if (scan == node->last) + break; + } + } + + IRO_Node = expr->node; + IRO_WalkTree(expr->linear, SetNodeNumInExprList); + } +} + +void IRO_InitList(IROList *list) { + list->head = list->tail = NULL; +} + +void IRO_AddToList(IROLinear *linear, IROList *list) { + if (list->head) + list->tail->next = linear; + else + list->head = linear; + + list->tail = linear; + while (list->tail->next) + list->tail = list->tail->next; +} + +IROLinear *IRO_FindLabelNode(CLabel *label, IROLinear *linear) { + IROLinear *scan; + + for (scan = linear; scan; scan = scan->next) { + if (scan->type == IROLinearLabel && scan->u.label.label == label) + break; + } + + CError_ASSERT(1244, scan); + return scan; +} + +void IRO_DuplicateExprRange(IROLinear *start, IROLinear *end, IROList *list) { + IROLinear *scan; + + for (scan = start; scan; scan = scan->next) { + if (scan->type != IROLinearNop && !(scan->flags & IROLF_Reffed)) + IRO_DuplicateExpr(scan, list); + if (scan == end) + break; + } +} + +IROLinear *IRO_DuplicateExpr(IROLinear *linear, IROList *list) { + IROLinear *copy; + ENode *copynode; + int i; + + copy = IRO_NewLinear(linear->type); + *copy = *linear; + + copy->index = ++IRO_NumLinear; + copy->next = NULL; + copy->expr = NULL; + + switch (copy->type) { + case IROLinearOperand: + copynode = lalloc(sizeof(ENode)); + *copynode = *linear->u.node; + copy->u.node = copynode; + break; + case IROLinearOp1Arg: + copy->u.monadic = IRO_DuplicateExpr(copy->u.monadic, list); + break; + case IROLinearOp2Arg: + if (linear->flags & IROLF_8000) { + copy->u.diadic.right = IRO_DuplicateExpr(copy->u.diadic.right, list); + copy->u.diadic.left = IRO_DuplicateExpr(copy->u.diadic.left, list); + } else { + copy->u.diadic.left = IRO_DuplicateExpr(copy->u.diadic.left, list); + copy->u.diadic.right = IRO_DuplicateExpr(copy->u.diadic.right, list); + } + break; + case IROLinearOp3Arg: + copy->u.args3.a = IRO_DuplicateExpr(copy->u.args3.a, list); + copy->u.args3.b = IRO_DuplicateExpr(copy->u.args3.b, list); + copy->u.args3.c = IRO_DuplicateExpr(copy->u.args3.c, list); + break; + case IROLinearFunccall: + copy->u.funccall.linear8 = IRO_DuplicateExpr(copy->u.funccall.linear8, list); + copy->u.funccall.args = oalloc(sizeof(IROLinear *) * copy->u.funccall.argCount); + for (i = 0; i < copy->u.funccall.argCount; i++) { + copy->u.funccall.args[i] = IRO_DuplicateExpr(linear->u.funccall.args[i], list); + } + break; + case IROLinearAsm: + copy->u.asm_stmt = CodeGen_CopyAsmStat(linear->u.asm_stmt); + break; + } + + IRO_AddToList(copy, list); + return copy; +} + +IROLinear *IRO_TempReference(Object *obj, IROList *list) { + IROLinear *op; + IROLinear *ind; + + op = IRO_NewLinear(IROLinearOperand); + op->u.node = create_objectrefnode(obj); + op->rtype = op->u.node->data.objref->type; + op->index = ++IRO_NumLinear; + op->flags |= IROLF_Reffed | IROLF_Ind; + IRO_AddToList(op, list); + + ind = IRO_NewLinear(IROLinearOp1Arg); + ind->nodetype = EINDIRECT; + ind->rtype = obj->type; + ind->u.monadic = op; + ind->index = ++IRO_NumLinear; + ind->next = NULL; + IRO_AddToList(ind, list); + + return ind; +} + +CW_INLINE IROLinear *LocateFatherHelper(IROLinear *linear, Boolean a, IROLinear ***b) { + IROLinear *scan; + SInt32 index; + int i; + + for (scan = linear->next, index = 0; index < (a ? 2 : 1); index++) { + while (scan) { + switch (scan->type) { + case IROLinearIf: + case IROLinearIfNot: + if (scan->u.label.x4 == linear) { + if (b) + *b = &scan->u.label.x4; + return scan; + } + break; + case IROLinearReturn: + if (scan->u.monadic == linear) { + if (b) + *b = &scan->u.monadic; + return scan; + } + break; + case IROLinearOp1Arg: + if (scan->u.monadic == linear) { + if (b) + *b = &scan->u.monadic; + return scan; + } + break; + case IROLinearSwitch: + if (scan->u.swtch.x4 == linear) { + if (b) + *b = &scan->u.swtch.x4; + return scan; + } + break; + case IROLinearOp2Arg: + if (scan->u.diadic.left == linear) { + if (b) + *b = &scan->u.diadic.left; + return scan; + } + if (scan->u.diadic.right == linear) { + if (b) + *b = &scan->u.diadic.right; + return scan; + } + break; + case IROLinearOp3Arg: + if (scan->u.args3.a == linear) { + if (b) + *b = &scan->u.args3.a; + return scan; + } + if (scan->u.args3.b == linear) { + if (b) + *b = &scan->u.args3.b; + return scan; + } + if (scan->u.args3.c == linear) { + if (b) + *b = &scan->u.args3.c; + return scan; + } + break; + case IROLinearFunccall: + if (scan->u.funccall.linear8 == linear) { + if (b) + *b = &scan->u.funccall.linear8; + return scan; + } + for (i = 0; i < scan->u.funccall.argCount; i++) { + if (scan->u.funccall.args[i] == linear) { + if (b) + *b = &scan->u.funccall.args[i]; + return scan; + } + } + break; + case IROLinearNop: + case IROLinearOperand: + case IROLinearGoto: + case IROLinearLabel: + case IROLinearEntry: + case IROLinearExit: + case IROLinearBeginCatch: + case IROLinearEndCatch: + case IROLinearEndCatchDtor: + case IROLinearAsm: + case IROLinearEnd: + break; + default: + CError_FATAL(1536); + } + scan = scan->next; + } + + scan = IRO_FirstLinear; + } + + if (b) + *b = NULL; + return NULL; +} + +IROLinear *IRO_LocateFather(IROLinear *linear) { + return LocateFatherHelper(linear, 0, NULL); +} + +IROLinear *IRO_LocateFather_Cut_And_Paste(IROLinear *a, IROLinear *b) { + IROLinear **p; + IROLinear *l = LocateFatherHelper(a, 0, &p); + if (l) { + CError_ASSERT(1568, p && *p); + IRO_NopOut(a); + *p = b; + } + return l; +} + +IROLinear *IRO_LocateFather_Cut_And_Paste_Without_Nopping(IROLinear *a, IROLinear *b) { + IROLinear **p; + IROLinear *l = LocateFatherHelper(a, 0, &p); + if (l) { + CError_ASSERT(1585, p && *p); + *p = b; + } + return l; +} + +void IRO_ReplaceReference(IROLinear *a, Object *obj, IROLinear *b) { + IROLinear **ptr; + IROList list; + + if (LocateFatherHelper(a, 1, &ptr)) { + CError_ASSERT(1605, ptr && *ptr); + IRO_InitList(&list); + *ptr = IRO_TempReference(obj, &list); + IRO_PasteAfter(list.head, list.tail, b); + if (a->flags & IROLF_LoopInvariant) + list.tail->flags |= IROLF_LoopInvariant; + } else { + IRO_Dump("Oh, oh, did not find reference to replace\n"); + } +} + +void IRO_ReplaceReferenceWithNode(IROLinear *a, IROLinear *b) { + IROLinear **ptr; + IROList list; + + if (LocateFatherHelper(a, 1, &ptr)) { + CError_ASSERT(1664, ptr && *ptr); + *ptr = b; + b->flags |= IROLF_Reffed; + } else { + IRO_Dump("Oh, oh, did not find reference to replace\n"); + } +} + +VarRecord *IRO_GetTemp(IROExpr *expr) { + expr->x8 = create_temp_object(expr->linear->rtype); + return IRO_FindVar(expr->x8, 1, 1); +} + +IROLinear *IRO_AssignToTemp(IROExpr *expr) { + IROLinear *objref; + IROLinear *ind; + IROLinear *ass; + + objref = IRO_NewLinear(IROLinearOperand); + objref->u.node = create_objectrefnode(expr->x8); + objref->rtype = objref->u.node->data.objref->type; + objref->index = ++IRO_NumLinear; + objref->flags |= IROLF_Reffed | IROLF_Assigned | IROLF_Ind; + + ind = IRO_NewLinear(IROLinearOp1Arg); + ind->nodetype = EINDIRECT; + ind->rtype = expr->linear->rtype; + ind->u.monadic = objref; + ind->index = ++IRO_NumLinear; + ind->flags |= IROLF_Reffed | IROLF_Assigned; + + ass = IRO_NewLinear(IROLinearOp2Arg); + ass->nodetype = EASS; + ass->u.diadic.left = ind; + ass->u.diadic.right = expr->linear; + ass->rtype = expr->linear->rtype; + ass->index = ++IRO_NumLinear; + + objref->next = ind; + ind->next = ass; + IRO_PasteAfter(objref, ass, expr->linear); + return ass; +} + +IROLinear *IRO_FindStart(IROLinear *linear) { + ExprStart = ExprEnd = linear; + IRO_WalkTree(linear, FindStart); + return ExprStart; +} + +void IRO_DeleteCommaNode(IROLinear *linear, IROExpr *expr) { + IROLinear *scan; + for (scan = linear; scan; scan = scan->next) { + if (scan->nodetype == ECOMMA) { + if (scan != expr->linear) { + IRO_NopOut(scan->u.diadic.left); + IRO_LocateFather_Cut_And_Paste(scan, scan->u.diadic.right); + } else { + IRO_NopOut(scan->u.diadic.left); + expr->linear = scan->u.diadic.right; + } + } + } +} + +void IRO_RemoveCommaNodeFromIR(void) { + IRONode *node; + IROLinear *linear; + + for (node = IRO_FirstNode; node; node = node->nextnode) { + linear = node->first; + do { + if (!linear) + break; + if (linear->nodetype == ECOMMA) { + linear->u.diadic.left->flags = linear->u.diadic.left->flags & ~IROLF_Reffed; + IRO_LocateFather_Cut_And_Paste_Without_Nopping(linear, linear->u.diadic.right); + linear->type = IROLinearNop; + } + linear = linear->next; + } while (linear != node->last); + } +} + +IROAddrRecord *IRO_InitAddrRecordPointer(IROLinear *linear) { + IROAddrRecord *rec = oalloc(sizeof(IROAddrRecord)); + rec->numObjRefs = 0; + rec->objRefs = NULL; + rec->numMisc = 0; + rec->misc = NULL; + rec->numInts = 0; + rec->ints = NULL; + rec->x16 = 0; + rec->linear = linear; + return rec; +} + +IROLinear *IRO_HasSideEffect(IROLinear *linear) { + IROLinear *tmp; + + if (!linear) + return linear; + + if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) + return linear; + + switch (linear->type) { + case IROLinearAsm: + return linear; + case IROLinearOperand: + if (ENODE_IS(linear->u.node, EOBJREF) && is_volatile_object(linear->u.node->data.objref)) + return linear; + return NULL; + case IROLinearOp1Arg: + if (IRO_IsAssignOp[linear->nodetype]) + return linear; + else + return IRO_HasSideEffect(linear->u.monadic); + case IROLinearOp2Arg: + if (IRO_IsAssignOp[linear->nodetype]) + return linear; + else if ((tmp = IRO_HasSideEffect(linear->u.diadic.left))) + return tmp; + else + return IRO_HasSideEffect(linear->u.diadic.right); + case IROLinearOp3Arg: + if ((tmp = IRO_HasSideEffect(linear->u.args3.a))) + return tmp; + else if ((tmp = IRO_HasSideEffect(linear->u.args3.b))) + return tmp; + else + return IRO_HasSideEffect(linear->u.args3.c); + case IROLinearFunccall: + return linear; + default: + return linear; + } +} + +IROLinear *IRO_CheckSideEffect(IROLinear *linear) { + IROLinear *result; + IROLinear *tmp; + IROLinear *tmp2; + IROLinear *tmp3; + + if (!linear) + return linear; + + if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) { + linear->flags &= ~IROLF_Reffed; + return linear; + } + + result = NULL; + switch (linear->type) { + case IROLinearAsm: + linear->flags &= ~IROLF_Reffed; + return linear; + case IROLinearOperand: + if (ENODE_IS(linear->u.node, EOBJREF) && is_volatile_object(linear->u.node->data.objref)) { + linear->flags &= ~IROLF_Reffed; + return linear; + } + break; + case IROLinearOp1Arg: + if (IRO_IsAssignOp[linear->nodetype]) { + linear->flags &= ~IROLF_Reffed; + return linear; + } + if ((result = IRO_CheckSideEffect(linear->u.monadic))) { + if (linear->nodetype == EINDIRECT && linear->u.monadic->type == IROLinearOperand) { + linear->flags &= ~IROLF_Reffed; + return linear; + } + } + break; + case IROLinearOp2Arg: + if (IRO_IsAssignOp[linear->nodetype]) { + linear->flags &= ~IROLF_Reffed; + return linear; + } + tmp = IRO_CheckSideEffect(linear->u.diadic.left); + tmp2 = IRO_CheckSideEffect(linear->u.diadic.right); + if (tmp) + result = tmp; + else + result = tmp2; + break; + case IROLinearOp3Arg: + tmp = IRO_CheckSideEffect(linear->u.args3.a); + tmp2 = IRO_CheckSideEffect(linear->u.args3.b); + tmp3 = IRO_CheckSideEffect(linear->u.args3.c); + result = tmp ? tmp : tmp2 ? tmp2 : tmp3; + break; + case IROLinearFunccall: + linear->flags &= ~IROLF_Reffed; + return linear; + default: + return linear; + } + + linear->type = IROLinearNop; + IRO_Dump("Nop out with side-effects checking at: %d\n", linear->index); + return result; +} + +void IRO_WalkExcActions(ExceptionAction *action, WalkObjFunc func) { + while (action) { + switch (action->type) { + case EAT_DESTROYLOCAL: + func(action->data.destroy_local.local); + break; + case EAT_DESTROYLOCALCOND: + func(action->data.destroy_local_cond.local); + func(action->data.destroy_local_cond.cond); + break; + case EAT_DESTROYLOCALOFFSET: + func(action->data.destroy_local_offset.local); + break; + case EAT_DESTROYLOCALPOINTER: + func(action->data.destroy_local_pointer.pointer); + break; + case EAT_DESTROYLOCALARRAY: + func(action->data.destroy_local_array.localarray); + break; + case EAT_DESTROYPARTIALARRAY: + func(action->data.destroy_partial_array.arraypointer); + func(action->data.destroy_partial_array.arraycounter); + func(action->data.destroy_partial_array.element_size); + break; + case EAT_DESTROYBASE: + func(action->data.destroy_member.objectptr); // wrong union? + break; + case EAT_DESTROYMEMBER: + func(action->data.destroy_member.objectptr); + break; + case EAT_DESTROYMEMBERCOND: + func(action->data.destroy_member_cond.objectptr); + func(action->data.destroy_member_cond.cond); + break; + case EAT_DESTROYMEMBERARRAY: + func(action->data.destroy_member_array.objectptr); + break; + case EAT_DELETEPOINTER: + func(action->data.delete_pointer.pointerobject); + break; + case EAT_DELETEPOINTERCOND: + func(action->data.delete_pointer_cond.pointerobject); + func(action->data.delete_pointer_cond.cond); + break; + } + action = action->prev; + } +} + +Boolean IRO_FunctionCallMightThrowException(IROLinear *linear) { + Object *obj; + if (linear->type == IROLinearFunccall) { + obj = NULL; + if (linear->u.funccall.linear8->type == IROLinearOperand && ENODE_IS(linear->u.funccall.linear8->u.node, EOBJREF)) + obj = linear->u.funccall.linear8->u.node->data.objref; + if (!obj || CExcept_CanThrowException(obj, obj->datatype == DVFUNC && !(linear->nodeflags & ENODE_FLAG_80))) + return 1; + } + return 0; +} + +IROLinear *IRO_NewIntConst(CInt64 val, Type *type) { + ENode *node; + IROLinear *linear; + + node = IRO_NewENode(EINTCONST); + node->data.intval = val; + node->rtype = type; + + linear = IRO_NewLinear(IROLinearOperand); + linear->index = ++IRO_NumLinear; + linear->rtype = type; + linear->u.node = node; + return linear; +} + +IROLinear *IRO_NewFloatConst(const Float val, Type *type) { + ENode *node; + IROLinear *linear; + + node = IRO_NewENode(EFLOATCONST); + node->data.floatval = val; + node->rtype = type; + + linear = IRO_NewLinear(IROLinearOperand); + linear->index = ++IRO_NumLinear; + linear->rtype = type; + linear->u.node = node; + return linear; +} + +Boolean IRO_IsAddressMultiply(IROLinear *linear) { + return 0; +} + +void IRO_SetupForUserBreakChecking(void) { + IRO_LastUserBreakTick = 0; +} + +void IRO_CheckForUserBreak(void) { + if (IRO_LastUserBreakTick + 8 < COS_GetTicks()) { + if (CWUserBreak(cparams.context)) + CError_UserBreak(); + IRO_LastUserBreakTick = COS_GetTicks(); + } +} diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroUtil.h b/compiler_and_linker/FrontEnd/Optimizer/IroUtil.h new file mode 100644 index 0000000..2661985 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroUtil.h @@ -0,0 +1,127 @@ +#ifndef COMPILER_IROUTIL_H +#define COMPILER_IROUTIL_H + +#include "IrOptimizer.h" +#include "compiler/CInt64.h" +#include "compiler/CParser.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +struct IROList { + IROLinear *head; + IROLinear *tail; +}; + +struct IROListNode { + IROList list; + IROListNode *nextList; +}; + +struct IROElmList { + void *element; + IROElmList *next; +}; + +struct IROAddrRecord { + IROLinear *linear; + unsigned short numObjRefs; + IROElmList *objRefs; + unsigned short numMisc; + IROElmList *misc; + unsigned short numInts; + IROElmList *ints; + int x16; +}; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +extern Object *FunctionName; +extern Boolean IRO_IsLeafFunction; +extern Boolean IRO_FunctionHasReturn; +extern Boolean DisableDueToAsm; +extern Boolean LoopOptimizerRun; + +extern Object *IRO_IsVariable(IROLinear *linear); +extern Boolean IRO_IsConstant(IROLinear *linear); +extern Boolean IRO_IsPow2(IROLinear *linear, SInt32 *powvalue); +extern Boolean IRO_IsIntConstant(IROLinear *linear); +extern Boolean IRO_IsFloatConstant(IROLinear *linear); +extern Boolean IRO_IsVector128Constant(IROLinear *linear); +extern Boolean IRO_IsAssignment(IROLinear *linear); +extern Boolean IRO_TypesEqual(Type *a, Type *b); +extern Type *IRO_UnsignedType(Type *type); +extern Type *IRO_SignedType(Type *type); +extern Boolean IRO_is_CPtypeequal(Type *a, Type *b); +extern Boolean IRO_ExprsSame(IROLinear *a, IROLinear *b); +extern CLabel *IRO_NewLabel(void); +extern Boolean IRO_ExprsSameSemantically(IROLinear *a, IROLinear *b); +extern IROLinear *IRO_FindPrecedAfter(IROLinear *a, IROLinear *iter); +extern IROLinear *IRO_FindPreced(IROLinear *a); +extern IROLinear *IRO_FindFirst(IROLinear *linear); +extern void IRO_CutAndPasteAfter(IROLinear *a, IROLinear *b, IROLinear *c); +extern Boolean IRO_IsConstantZero(IROLinear *linear); +extern Boolean IRO_IsConstantOne(IROLinear *linear); +extern Boolean IRO_IsConstantNegativeOne(IROLinear *linear); +extern void IRO_NopOut(IROLinear *linear); +extern void IRO_NopNonSideEffects(IROLinear *linear, SInt32 level); +extern void IRO_BuildList(IROLinear *linear, Boolean isEntry); +typedef void (*IROWalkTreeFunc)(IROLinear *linear, Boolean isEntry); +extern void IRO_WalkTree(IROLinear *linear, IROWalkTreeFunc func); +extern void IRO_WalkTreeToPropagateFlags(IROLinear *linear, IROWalkTreeFunc func); +extern void IRO_WalkInts(IROLinear *a, IROLinear *b, IROWalkTreeFunc func); +extern void IRO_Cut(IROLinear *a, IROLinear *b); +extern void IRO_Paste(IROLinear *a, IROLinear *b, IROLinear *c); +extern void IRO_PasteAfter(IROLinear *a, IROLinear *b, IROLinear *c); +extern void IRO_ClipExpr(IROExpr *expr); +extern void IRO_ClipExprTree(IROLinear *linear); +extern void IRO_MoveExpression(IROExpr *expr, IROLinear *linear); +extern void IRO_InitList(IROList *list); +extern void IRO_AddToList(IROLinear *linear, IROList *list); +extern IROLinear *IRO_FindLabelNode(CLabel *label, IROLinear *linear); +extern void IRO_DuplicateExprRange(IROLinear *start, IROLinear *end, IROList *list); +extern IROLinear *IRO_DuplicateExpr(IROLinear *linear, IROList *list); +extern IROLinear *IRO_TempReference(Object *obj, IROList *list); +extern IROLinear *IRO_LocateFather(IROLinear *linear); +extern IROLinear *IRO_LocateFather_Cut_And_Paste(IROLinear *a, IROLinear *b); +extern IROLinear *IRO_LocateFather_Cut_And_Paste_Without_Nopping(IROLinear *a, IROLinear *b); +extern void IRO_ReplaceReference(IROLinear *a, Object *obj, IROLinear *b); +extern void IRO_ReplaceReferenceWithNode(IROLinear *a, IROLinear *b); +extern VarRecord *IRO_GetTemp(IROExpr *expr); +extern IROLinear *IRO_AssignToTemp(IROExpr *expr); +extern IROLinear *IRO_FindStart(IROLinear *linear); +extern void IRO_DeleteCommaNode(IROLinear *linear, IROExpr *expr); +extern void IRO_RemoveCommaNodeFromIR(void); +extern IROAddrRecord *IRO_InitAddrRecordPointer(IROLinear *linear); +extern IROLinear *IRO_HasSideEffect(IROLinear *linear); +extern IROLinear *IRO_CheckSideEffect(IROLinear *linear); +typedef void (*WalkObjFunc)(Object *obj); +extern void IRO_WalkExcActions(ExceptionAction *action, WalkObjFunc func); +extern Boolean IRO_FunctionCallMightThrowException(IROLinear *linear); +extern IROLinear *IRO_NewIntConst(CInt64 val, Type *type); +extern IROLinear *IRO_NewFloatConst(const Float val, Type *type); +extern Boolean IRO_IsAddressMultiply(IROLinear *linear); +extern void IRO_SetupForUserBreakChecking(void); +extern void IRO_CheckForUserBreak(void); + +// TODO is this elsewhere? +CW_INLINE Boolean IRO_IsUnsignedType(Type *type) { + return is_unsigned(type); +} + +// 4B4D40 +CW_INLINE CInt64 IRO_MakeULong(UInt32 i) { + CInt64 val; + CInt64_SetULong(&val, i); + return val; +} + +// 4BAAA0 +CW_INLINE CInt64 IRO_MakeLong(SInt32 i) { + CInt64 val; + CInt64_SetLong(&val, i); + return val; +} + +#endif diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroVars.c b/compiler_and_linker/FrontEnd/Optimizer/IroVars.c new file mode 100644 index 0000000..b72ba89 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroVars.c @@ -0,0 +1,1430 @@ +#include "IroVars.h" +#include "IroDump.h" +#include "IroFlowgraph.h" +#include "IroJump.h" +#include "IroLinearForm.h" +#include "IroMalloc.h" +#include "IroPointerAnalysis.h" +#include "IroUtil.h" +#include "IROUseDef.h" +#include "compiler/CClass.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CParser.h" +#include "compiler/CompilerTools.h" +#include "compiler/Exceptions.h" +#include "compiler/objects.h" +#include "compiler/InlineAsm.h" +#include "compiler/InlineAsmPPC.h" +#include "BitVector.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct IndirectRecordMatch { + IROLinear *nd; + struct IndirectRecordMatch *otherMatches; +} IndirectRecordMatch; + +typedef struct IndirectRecord { + IROLinear *linear; + unsigned char flags; + VarRecord *var; + SInt32 addend; + SInt32 size; + int startbit; + int endbit; + Type *type; + struct IndirectRecord *next; + IndirectRecordMatch *matches; + IROLinear *x26; +} IndirectRecord; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static IndirectRecord *IRO_FirstIndirectRecord; +static IndirectRecord *IRO_LastIndirectRecord; +static IROLinear *TheBaseTerm; +VarRecord *IRO_FirstVar; +VarRecord *IRO_LastVar; +SInt32 IRO_NumVars; +Boolean IRO_IsBitField; +SInt32 IRO_BaseTerms; +SInt32 IRO_VarTerms; +Boolean IRO_IsModifyOp[MAXEXPR]; +Boolean IRO_IsAssignOp[MAXEXPR]; + +// forward decls +static Boolean CheckAddress(IROLinear *nd, Boolean *resultFlag); +static Boolean CheckAddressConsistency(IROLinear *nd, VarRecord *var, SInt32 addend, Type *type); +static void DisableEntries(IndirectRecord *irec); +static void DisableAddressedEntries(void); +static UInt32 ObjectIsArg(Object *obj); + +void IRO_InitializeIRO_IsModifyOpArray(void) { + int i; + + for (i = 0; i < MAXEXPR; i++) + IRO_IsModifyOp[i] = 0; + + IRO_IsModifyOp[EPOSTINC] = 1; + IRO_IsModifyOp[EPOSTDEC] = 1; + IRO_IsModifyOp[EPREINC] = 1; + IRO_IsModifyOp[EPREDEC] = 1; + IRO_IsModifyOp[EINDIRECT] = 0; + IRO_IsModifyOp[EMONMIN] = 0; + IRO_IsModifyOp[EBINNOT] = 0; + IRO_IsModifyOp[ELOGNOT] = 0; + IRO_IsModifyOp[EFORCELOAD] = 0; + IRO_IsModifyOp[EMUL] = 0; + IRO_IsModifyOp[EMULV] = 0; + IRO_IsModifyOp[EDIV] = 0; + IRO_IsModifyOp[EMODULO] = 0; + IRO_IsModifyOp[EADDV] = 0; + IRO_IsModifyOp[ESUBV] = 0; + IRO_IsModifyOp[EADD] = 0; + IRO_IsModifyOp[ESUB] = 0; + IRO_IsModifyOp[ESHL] = 0; + IRO_IsModifyOp[ESHR] = 0; + IRO_IsModifyOp[ELESS] = 0; + IRO_IsModifyOp[EGREATER] = 0; + IRO_IsModifyOp[ELESSEQU] = 0; + IRO_IsModifyOp[EGREATEREQU] = 0; + IRO_IsModifyOp[EEQU] = 0; + IRO_IsModifyOp[ENOTEQU] = 0; + IRO_IsModifyOp[EAND] = 0; + IRO_IsModifyOp[EXOR] = 0; + IRO_IsModifyOp[EOR] = 0; + IRO_IsModifyOp[ELAND] = 0; + IRO_IsModifyOp[ELOR] = 0; + IRO_IsModifyOp[EASS] = 0; + IRO_IsModifyOp[EMULASS] = 1; + IRO_IsModifyOp[EDIVASS] = 1; + IRO_IsModifyOp[EMODASS] = 1; + IRO_IsModifyOp[EADDASS] = 1; + IRO_IsModifyOp[ESUBASS] = 1; + IRO_IsModifyOp[ESHLASS] = 1; + IRO_IsModifyOp[ESHRASS] = 1; + IRO_IsModifyOp[EANDASS] = 1; + IRO_IsModifyOp[EXORASS] = 1; + IRO_IsModifyOp[EORASS] = 1; + IRO_IsModifyOp[ECOMMA] = 0; + IRO_IsModifyOp[EPMODULO] = 1; + IRO_IsModifyOp[EROTL] = 1; + IRO_IsModifyOp[EROTR] = 1; + IRO_IsModifyOp[EBCLR] = 1; + IRO_IsModifyOp[EBTST] = 1; + IRO_IsModifyOp[EBSET] = 1; + IRO_IsModifyOp[ETYPCON] = 0; + IRO_IsModifyOp[EBITFIELD] = 0; + IRO_IsModifyOp[EINTCONST] = 0; + IRO_IsModifyOp[EFLOATCONST] = 0; + IRO_IsModifyOp[ESTRINGCONST] = 0; + IRO_IsModifyOp[ECOND] = 0; + IRO_IsModifyOp[EFUNCCALL] = 0; + IRO_IsModifyOp[EFUNCCALLP] = 0; + IRO_IsModifyOp[EOBJREF] = 0; + IRO_IsModifyOp[EMFPOINTER] = 0; + IRO_IsModifyOp[ENULLCHECK] = 0; + IRO_IsModifyOp[EPRECOMP] = 0; + IRO_IsModifyOp[ETEMP] = 0; + IRO_IsModifyOp[EARGOBJ] = 0; + IRO_IsModifyOp[ELOCOBJ] = 0; + IRO_IsModifyOp[ELABEL] = 0; + IRO_IsModifyOp[ESETCONST] = 0; + IRO_IsModifyOp[ENEWEXCEPTION] = 0; + IRO_IsModifyOp[ENEWEXCEPTIONARRAY] = 0; + IRO_IsModifyOp[EOBJLIST] = 0; + IRO_IsModifyOp[EMEMBER] = 0; + IRO_IsModifyOp[ETEMPLDEP] = 0; + IRO_IsModifyOp[EINSTRUCTION] = 0; + IRO_IsModifyOp[EDEFINE] = 0; + IRO_IsModifyOp[EREUSE] = 0; + IRO_IsModifyOp[EASSBLK] = 0; + IRO_IsModifyOp[EVECTOR128CONST] = 0; + IRO_IsModifyOp[ECONDASS] = 1; +} + +void IRO_InitializeIRO_IsAssignOpArray(void) { + int i; + + for (i = 0; i < MAXEXPR; i++) + IRO_IsAssignOp[i] = 0; + + IRO_IsAssignOp[EPOSTINC] = 1; + IRO_IsAssignOp[EPOSTDEC] = 1; + IRO_IsAssignOp[EPREINC] = 1; + IRO_IsAssignOp[EPREDEC] = 1; + IRO_IsAssignOp[EINDIRECT] = 0; + IRO_IsAssignOp[EMONMIN] = 0; + IRO_IsAssignOp[EBINNOT] = 0; + IRO_IsAssignOp[ELOGNOT] = 0; + IRO_IsAssignOp[EFORCELOAD] = 0; + IRO_IsAssignOp[EMUL] = 0; + IRO_IsAssignOp[EMULV] = 0; + IRO_IsAssignOp[EDIV] = 0; + IRO_IsAssignOp[EMODULO] = 0; + IRO_IsAssignOp[EADDV] = 0; + IRO_IsAssignOp[ESUBV] = 0; + IRO_IsAssignOp[EADD] = 0; + IRO_IsAssignOp[ESUB] = 0; + IRO_IsAssignOp[ESHL] = 0; + IRO_IsAssignOp[ESHR] = 0; + IRO_IsAssignOp[ELESS] = 0; + IRO_IsAssignOp[EGREATER] = 0; + IRO_IsAssignOp[ELESSEQU] = 0; + IRO_IsAssignOp[EGREATEREQU] = 0; + IRO_IsAssignOp[EEQU] = 0; + IRO_IsAssignOp[ENOTEQU] = 0; + IRO_IsAssignOp[EAND] = 0; + IRO_IsAssignOp[EXOR] = 0; + IRO_IsAssignOp[EOR] = 0; + IRO_IsAssignOp[ELAND] = 0; + IRO_IsAssignOp[ELOR] = 0; + IRO_IsAssignOp[EASS] = 1; + IRO_IsAssignOp[EMULASS] = 1; + IRO_IsAssignOp[EDIVASS] = 1; + IRO_IsAssignOp[EMODASS] = 1; + IRO_IsAssignOp[EADDASS] = 1; + IRO_IsAssignOp[ESUBASS] = 1; + IRO_IsAssignOp[ESHLASS] = 1; + IRO_IsAssignOp[ESHRASS] = 1; + IRO_IsAssignOp[EANDASS] = 1; + IRO_IsAssignOp[EXORASS] = 1; + IRO_IsAssignOp[EORASS] = 1; + IRO_IsAssignOp[ECOMMA] = 0; + IRO_IsAssignOp[EPMODULO] = 1; + IRO_IsAssignOp[EROTL] = 1; + IRO_IsAssignOp[EROTR] = 1; + IRO_IsAssignOp[EBCLR] = 1; + IRO_IsAssignOp[EBTST] = 1; + IRO_IsAssignOp[EBSET] = 1; + IRO_IsAssignOp[ETYPCON] = 0; + IRO_IsAssignOp[EBITFIELD] = 0; + IRO_IsAssignOp[EINTCONST] = 0; + IRO_IsAssignOp[EFLOATCONST] = 0; + IRO_IsAssignOp[ESTRINGCONST] = 0; + IRO_IsAssignOp[ECOND] = 0; + IRO_IsAssignOp[EFUNCCALL] = 0; + IRO_IsAssignOp[EFUNCCALLP] = 0; + IRO_IsAssignOp[EOBJREF] = 0; + IRO_IsAssignOp[EMFPOINTER] = 0; + IRO_IsAssignOp[ENULLCHECK] = 0; + IRO_IsAssignOp[EPRECOMP] = 0; + IRO_IsAssignOp[ETEMP] = 0; + IRO_IsAssignOp[EARGOBJ] = 0; + IRO_IsAssignOp[ELOCOBJ] = 0; + IRO_IsAssignOp[ELABEL] = 0; + IRO_IsAssignOp[ESETCONST] = 0; + IRO_IsAssignOp[ENEWEXCEPTION] = 0; + IRO_IsAssignOp[ENEWEXCEPTIONARRAY] = 0; + IRO_IsAssignOp[EOBJLIST] = 0; + IRO_IsAssignOp[EMEMBER] = 0; + IRO_IsAssignOp[ETEMPLDEP] = 0; + IRO_IsAssignOp[EINSTRUCTION] = 0; + IRO_IsAssignOp[EDEFINE] = 0; + IRO_IsAssignOp[EREUSE] = 0; + IRO_IsAssignOp[EASSBLK] = 0; + IRO_IsAssignOp[EVECTOR128CONST] = 0; + IRO_IsAssignOp[ECONDASS] = 1; +} + +VarRecord *IRO_FindVar(Object *object, Boolean flag1, Boolean flag2) { + VarRecord *var; + VarInfo *vi; + + var = object->varptr; + if (!var && flag1) { + vi = NULL; + if (object->datatype == DLOCAL) + vi = object->u.var.info; + if (vi) + vi->usage = 0; + var = oalloc(sizeof(VarRecord)); + var->object = object; + var->index = ++IRO_NumVars; + var->x6 = 0; + var->xA = 0; + var->next = NULL; + var->defs = NULL; + var->uses = NULL; + var->x1A = NULL; + var->x1E = NULL; + var->xB = 0; + if (IRO_FirstVar) + IRO_LastVar->next = var; + else + IRO_FirstVar = var; + IRO_LastVar = var; + object->varptr = var; + } + + if (var && !flag2) { + var->xB = 1; + if (object->datatype == DLOCAL && object->u.var.info && object->u.var.info->noregister == 0) + object->u.var.info->noregister = 2; + } + + return var; +} + +static void ResetVars(void) { + VarRecord *var; + + for (var = IRO_FirstVar; var; var = var->next) { + var->xB = 0; + if (var->object && var->object->datatype == DLOCAL && var->object->u.var.info) { + if (var->object->u.var.info->noregister == 2) + var->object->u.var.info->noregister = 0; + } + } +} + +static void IRO_HandleExceptionActions(IROLinear *linear) { + ExceptionAction *action; + + for (action = linear->stmt->dobjstack; action; action = action->prev) { + switch (action->type) { + case EAT_DESTROYLOCAL: + IRO_FindVar(action->data.destroy_local.local, 1, 0); + break; + case EAT_DESTROYLOCALCOND: + IRO_FindVar(action->data.destroy_local_cond.local, 1, 0); + break; + case EAT_DESTROYLOCALOFFSET: + IRO_FindVar(action->data.destroy_local_offset.local, 1, 0); + break; + case EAT_DESTROYLOCALARRAY: + IRO_FindVar(action->data.destroy_local_array.localarray, 1, 0); + break; + case EAT_DESTROYMEMBER: + case EAT_DESTROYBASE: + IRO_FindVar(action->data.destroy_member.objectptr, 1, 0); + break; + case EAT_DESTROYMEMBERCOND: + IRO_FindVar(action->data.destroy_member_cond.objectptr, 1, 0); + break; + case EAT_DESTROYMEMBERARRAY: + IRO_FindVar(action->data.destroy_member_array.objectptr, 1, 0); + break; + case EAT_CATCHBLOCK: + if (action->data.catch_block.catch_object) + IRO_FindVar(action->data.catch_block.catch_object, 1, 0); + IRO_FindVar(action->data.catch_block.catch_info_object, 1, 0); + break; + case EAT_ACTIVECATCHBLOCK: + IRO_FindVar(action->data.active_catch_block.catch_info_object, 1, 0); + break; + } + } +} + +void IRO_FindAllVars(void) { + IROLinear *linear; + VarRecord *var; + + linear = IRO_FirstLinear; + IRO_NumVars = 0; + IRO_FirstVar = IRO_LastVar = NULL; + + while (linear) { + if (IS_LINEAR_ENODE(linear, EOBJREF)) { + if (Inline_IsObjectData(linear->u.node->data.objref) || linear->u.node->data.objref->datatype == DLOCAL) + IRO_FindVar(linear->u.node->data.objref, 1, (linear->flags & IROLF_Ind) != 0); + else + linear->u.node->data.objref->varptr = NULL; + } else if (linear->type == IROLinearFunccall) { + if (linear->stmt && IRO_FunctionCallMightThrowException(linear)) + IRO_HandleExceptionActions(linear); + } else if (linear->type == IROLinearAsm) { + IAEffects effects; + int i; + CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects); + for (i = 0; i < effects.numoperands; i++) + IRO_FindVar(effects.operands[i].object, 1, effects.operands[i].type != IAEffect_3); + } + linear = linear->next; + } + + var = IRO_FirstVar; + Bv_AllocVector(&IRO_FuncKills, IRO_NumVars + 1); + Bv_SetBit(0, IRO_FuncKills); + while (var) { + if (Inline_IsObjectData(var->object) || var->xB) + Bv_SetBit(var->index, IRO_FuncKills); + var = var->next; + } + + IRO_CheckForUserBreak(); +} + +void IRO_ZapVarPtrs(void) { + VarRecord *var; + + for (var = IRO_FirstVar; var; var = var->next) + var->object->varptr = NULL; +} + +void IRO_UpdateVars(void) { + IROLinear *linear; + VarRecord *var; + + ResetVars(); + + for (linear = IRO_FirstLinear; linear; linear = linear->next) { + if (IS_LINEAR_ENODE(linear, EOBJREF)) { + if (Inline_IsObjectData(linear->u.node->data.objref) || linear->u.node->data.objref->datatype == DLOCAL) + IRO_FindVar(linear->u.node->data.objref, 0, (linear->flags & IROLF_Ind) || !(linear->flags & IROLF_Reffed)); + } else if (linear->type == IROLinearFunccall) { + if (linear->stmt && IRO_FunctionCallMightThrowException(linear)) + IRO_HandleExceptionActions(linear); + } else if (linear->type == IROLinearAsm) { + IAEffects effects; + int i; + CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects); + for (i = 0; i < effects.numoperands; i++) + IRO_FindVar(effects.operands[i].object, 0, effects.operands[i].type != IAEffect_3); + } + } + + var = IRO_FirstVar; + Bv_AllocVector(&IRO_FuncKills, IRO_NumVars + 1); + Bv_SetBit(0, IRO_FuncKills); + while (var) { + if (Inline_IsObjectData(var->object) || var->xB) + Bv_SetBit(var->index, IRO_FuncKills); + var = var->next; + } +} + +void IRO_AddElmToList(IROLinear *linear, IROElmList **list) { + IROElmList *l = oalloc(sizeof(IROElmList)); + l->element = linear; + l->next = NULL; + if (!*list) { + *list = l; + } else { + l->next = *list; + *list = l; + } +} + +void IRO_DecomposeAddressExpression(IROLinear *linear, IROAddrRecord *rec) { + if (IS_LINEAR_DIADIC(linear->u.diadic.left, EADD)) { + IRO_DecomposeAddressExpression(linear->u.diadic.left, rec); + } else if (IS_LINEAR_ENODE(linear->u.diadic.left, EINTCONST)) { + rec->numInts++; + IRO_AddElmToList(linear->u.diadic.left, &rec->ints); + } else if (IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF)) { + rec->numObjRefs++; + IRO_AddElmToList(linear->u.diadic.left, &rec->objRefs); + } else { + rec->numMisc++; + IRO_AddElmToList(linear->u.diadic.left, &rec->misc); + } + + if (IS_LINEAR_DIADIC(linear->u.diadic.right, EADD)) { + IRO_DecomposeAddressExpression(linear->u.diadic.right, rec); + } else if (IS_LINEAR_ENODE(linear->u.diadic.right, EINTCONST)) { + rec->numInts++; + IRO_AddElmToList(linear->u.diadic.right, &rec->ints); + } else if (IS_LINEAR_ENODE(linear->u.diadic.right, EOBJREF)) { + rec->numObjRefs++; + IRO_AddElmToList(linear->u.diadic.right, &rec->objRefs); + } else { + rec->numMisc++; + IRO_AddElmToList(linear->u.diadic.right, &rec->misc); + } +} + +void IRO_DecomposeAddressExpression_Cheap(IROLinear *linear) { + if (IS_LINEAR_DIADIC(linear->u.diadic.left, EADD)) { + IRO_DecomposeAddressExpression_Cheap(linear->u.diadic.left); + } else if (!IS_LINEAR_ENODE(linear->u.diadic.left, EINTCONST)) { + if (IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF)) { + IRO_BaseTerms++; + TheBaseTerm = linear->u.diadic.left; + } else { + IRO_VarTerms++; + } + } + + if (IS_LINEAR_DIADIC(linear->u.diadic.right, EADD)) { + IRO_DecomposeAddressExpression_Cheap(linear->u.diadic.right); + } else if (!IS_LINEAR_ENODE(linear->u.diadic.right, EINTCONST)) { + if (IS_LINEAR_ENODE(linear->u.diadic.right, EOBJREF)) { + IRO_BaseTerms++; + TheBaseTerm = linear->u.diadic.right; + } else { + IRO_VarTerms++; + } + } +} + +VarRecord *IRO_FindAssigned(IROLinear *linear) { + VarRecord *rec; + + IRO_IsBitField = 0; + if (linear->type == IROLinearOp2Arg) + linear = linear->u.diadic.left; + else if (linear->type == IROLinearOp1Arg) + linear = linear->u.monadic; + else + CError_FATAL(818); + + if (IS_LINEAR_MONADIC(linear, EINDIRECT)) + linear = linear->u.monadic; + + if (IS_LINEAR_MONADIC(linear, EBITFIELD)) { + IRO_IsBitField = 1; + linear = linear->u.monadic; + } + + if (IS_LINEAR_DIADIC(linear, EADD)) { + if (IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF) && IS_LINEAR_ENODE(linear->u.diadic.right, EINTCONST)) { + linear = linear->u.diadic.left; + } else { + IRO_BaseTerms = 0; + IRO_DecomposeAddressExpression_Cheap(linear); + if (IRO_BaseTerms == 1) + linear = TheBaseTerm; + } + } + + if (!IS_LINEAR_ENODE(linear, EOBJREF)) + return NULL; + + if ((rec = IRO_FindVar(linear->u.node->data.objref, 0, 1))) + return rec; + else + return NULL; +} + +static void GetKillsByIndirectAssignment(IROLinear *linear) { + IROListNode *resultList; + IROLinear *nd; + IROListNode *list; + IROListNode *scan; + IROLinear *inner; + Boolean result; + Boolean foundLinear; + + result = 0; + + if (linear->type == IROLinearOp2Arg) + linear = linear->u.diadic.left; + else + linear = linear->u.monadic; + + if ( + linear && + linear->type == IROLinearOp1Arg && + linear->nodetype == EINDIRECT && + (inner = linear->u.monadic) && + copts.opt_pointer_analysis && + inner->pointsToFunction && + FunctionName + ) + { + resultList = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, inner, &resultList); + if ((list = resultList)) { + for (scan = list; scan; scan = scan->nextList) { + if (!scan->list.head || !scan->list.tail) { + result = 1; + break; + } + + foundLinear = 0; + for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) { + if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { + foundLinear = 1; + break; + } + } + if (!foundLinear) { + result = 1; + break; + } + } + + if (!result) { + while (list) { + for (nd = list->list.head; nd != list->list.tail->next; nd = nd->next) { + if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { + Object *obj; + VarRecord *var; + int index; + + obj = nd->u.node->data.objref; + CError_ASSERT(952, obj != NULL); + + var = IRO_FindVar(obj, 1, 1); + CError_ASSERT(954, var != NULL); + + index = var->index; + CError_ASSERT(956, index != 0); + + Bv_SetBit(index, IRO_VarKills); + } + } + + list = list->nextList; + } + } + + while (resultList) { + IROListNode *next = resultList->nextList; + IRO_free(resultList); + resultList = next; + } + } else { + result = 1; + } + } else { + result = 1; + } + + if (result) + Bv_Or(IRO_FuncKills, IRO_VarKills); +} + +static void GetKillsByFunctionCall(IROLinear *linear) { + IROListNode *resultList; + IROLinear *nd; + IROListNode *list; + IROListNode *scan; + IROLinear *inner; + Boolean result; + Boolean foundLinear; + Object *obj; + ObjectList *killList; + ObjectList *olist; + + result = 0; + + if ( + (inner = linear->u.funccall.linear8) && + copts.opt_pointer_analysis && + inner->pointsToFunction && + FunctionName + ) + { + resultList = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, inner, &resultList); + if (resultList) { + for (scan = resultList; scan; scan = scan->nextList) { + if (!scan->list.head || !scan->list.tail) { + result = 1; + break; + } + + foundLinear = 0; + for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) { + if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { + foundLinear = 1; + obj = nd->u.node->data.objref; + CError_ASSERT(1028, obj != NULL); + + killList = NULL; + PointerAnalysis_GetFunctionKills(obj, linear, &killList); + + for (olist = killList; olist; olist = olist->next) { + if (!olist->object) { + result = 1; + break; + } + } + + while (killList) { + ObjectList *next = killList->next; + IRO_free(killList); + killList = next; + } + + if (result) + break; + } + } + + if (!foundLinear) + result = 1; + if (result) + break; + } + + if (!result) { + for (scan = resultList; scan; scan = scan->nextList) { + for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) { + if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { + obj = nd->u.node->data.objref; + killList = NULL; + PointerAnalysis_GetFunctionKills(obj, linear, &killList); + + for (olist = killList; olist; olist = olist->next) { + VarRecord *var; + int index; + + var = IRO_FindVar(olist->object, 1, 1); + CError_ASSERT(1079, var != NULL); + + index = var->index; + CError_ASSERT(1081, index != 0); + + Bv_SetBit(index, IRO_VarKills); + } + + while (killList) { + ObjectList *next = killList->next; + IRO_free(killList); + killList = next; + } + } + } + } + } + + while (resultList) { + IROListNode *next = resultList->nextList; + IRO_free(resultList); + resultList = next; + } + } else { + result = 1; + } + } else { + result = 1; + } + + if (result) + Bv_Or(IRO_FuncKills, IRO_VarKills); +} + +void IRO_GetKills(IROLinear *linear) { + VarRecord *var; + + switch (linear->type) { + case IROLinearOp1Arg: + case IROLinearOp2Arg: + if (IRO_IsAssignOp[linear->nodetype]) { + IROLinear *assigned; + int index; + + var = IRO_FindAssigned(linear); + index = 0; + if (var) index = var->index; + Bv_SetBit(index, IRO_VarKills); + + if (!index) + GetKillsByIndirectAssignment(linear); + } + break; + case IROLinearFunccall: + GetKillsByFunctionCall(linear); + break; + case IROLinearAsm: { + IAEffects effects; + int i; + + CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects); + for (i = 0; i < effects.numoperands; i++) { + switch (effects.operands[i].type) { + case IAEffect_1: + case IAEffect_2: + case IAEffect_4: + if ((var = IRO_FindVar(effects.operands[i].object, 0, 1))) + Bv_SetBit(var->index, IRO_VarKills); + break; + } + } + + if (effects.x1 || effects.x4) + Bv_Or(IRO_FuncKills, IRO_VarKills); + break; + } + } +} + +void IRO_CheckInit(void) { + IRONode *fnode; + IROLinear *nd; + VarRecord *var; + ObjectList *olist; + int flag; + int i; + BitVector *bv; + + IRO_MakeReachable(IRO_FirstNode); + fnode = IRO_FirstNode; + Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1); + + while (fnode) { + Bv_AllocVector(&fnode->x16, IRO_NumVars + 1); + Bv_AllocVector(&fnode->x1E, IRO_NumVars + 1); + + for (nd = fnode->first; nd; nd = nd->next) { + if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) { + if (nd->flags & IROLF_Ind) { + if (!(nd->flags & IROLF_Assigned) || (nd->flags & IROLF_Used)) { + if ((var = IRO_FindVar(nd->u.node->data.objref, 0, 1))) { + if (!Bv_IsBitSet(var->index, fnode->x1E)) + Bv_SetBit(var->index, fnode->x16); + } + } + } else { + if ((var = IRO_FindVar(nd->u.node->data.objref, 0, 0))) { + Bv_SetBit(var->index, fnode->x1E); + } + } + } else if (nd->type == IROLinearOp2Arg && nd->nodetype == EASS) { + if ((var = IRO_FindAssigned(nd))) + Bv_SetBit(var->index, fnode->x1E); + } else if (nd->type == IROLinearAsm) { + IAEffects effects; + + CodeGen_GetAsmEffects(nd->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_1: + case IAEffect_2: + case IAEffect_4: + Bv_SetBit(var->index, fnode->x1E); + break; + } + } + } + + if (nd == fnode->last) + break; + } + + fnode = fnode->nextnode; + } + + Bv_AllocVector(&bv, IRO_NumVars + 1); + + do { + flag = 0; + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + Bv_Copy(fnode->x1E, bv); + for (i = 0; i < fnode->numpred; i++) + Bv_Or(IRO_NodeTable[fnode->pred[i]]->x1E, bv); + if (!Bv_Compare(bv, fnode->x1E)) { + Bv_Copy(bv, fnode->x1E); + flag = 1; + } + } + } while (flag); + + Bv_Clear(IRO_VarKills); + + for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) { + if (fnode->x36) { + Bv_Copy(fnode->x16, bv); + for (i = 0; i < fnode->numpred; i++) + Bv_Minus(IRO_NodeTable[fnode->pred[i]]->x1E, bv); + Bv_Or(bv, IRO_VarKills); + } + } + + for (olist = locals; olist; olist = olist->next) { + if ((var = IRO_FindVar(olist->object, 0, 1)) && Bv_IsBitSet(var->index, IRO_VarKills)) { + VarInfo *vi = olist->object->u.var.info; + if (!IsTempName(olist->object->name) && !is_volatile_object(olist->object)) { + if (!IS_TYPE_CLASS(olist->object->type) || !CClass_IsEmpty(TYPE_CLASS(olist->object->type))) { + CError_SetErrorToken(&vi->deftoken); + CError_Warning(CErrorStr185, olist->object->name->name); + } + } + } + } + + IRO_CheckForUserBreak(); +} + +static void RewriteIndDec(void) { + IROLinear *add; + IROLinear *indirect; + IROLinear *Int; + IROLinear *nd; + CInt64 value; + IROList list; + + for (nd = IRO_FirstLinear; nd; nd = nd->next) { + if ( + nd->type == IROLinearOp1Arg && + (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC) && + !(nd->flags & IROLF_Reffed) + ) { + indirect = nd->u.monadic; + if ( + indirect->type == IROLinearOp1Arg && + indirect->nodetype == EINDIRECT && + indirect->u.monadic->type == IROLinearOp1Arg && + indirect->u.monadic->nodetype == EBITFIELD + ) { + value = IRO_GetSelfAssignmentVal(nd); + IRO_InitList(&list); + + nd->type = IROLinearOp2Arg; + nd->nodetype = EASS; + nd->u.diadic.left = indirect; + IRO_DuplicateExpr(indirect, &list); + + Int = IRO_NewIntConst(value, indirect->rtype); + Int->flags |= IROLF_Used | IROLF_Reffed; + + add = IRO_NewLinear(IROLinearOp2Arg); + add->nodetype = EADD; + add->u.diadic.left = list.tail; + add->u.diadic.left->flags = 0; + add->u.diadic.left->flags |= IROLF_Used | IROLF_Reffed; + add->u.diadic.right = Int; + add->rtype = indirect->rtype; + add->flags = 0; + add->flags |= IROLF_Used | IROLF_Reffed; + + nd->u.diadic.right = add; + + IRO_AddToList(Int, &list); + IRO_AddToList(add, &list); + IRO_PasteAfter(list.head, list.tail, indirect); + } + } + } +} + +void IRO_RewriteBitFieldTemps(void) { + IROLinear *nd; + IROLinear *expr2; + Object *obj; + VarRecord *var; + IROList list; + + for (nd = IRO_FirstLinear; nd; nd = nd->next) { + if ((obj = IRO_IsVariable(nd)) && (nd->flags & IROLF_BitfieldIndirect)) { + var = IRO_FindVar(obj, 0, 1); + CError_ASSERT(1526, var != NULL); + + expr2 = var->x1E; + CError_ASSERT(1532, expr2 != NULL); + + IRO_InitList(&list); + IRO_DuplicateExpr(expr2, &list); + IRO_NopOut(nd->u.monadic); + nd->u.monadic = list.tail; + IRO_Paste(list.head, list.tail, nd); + } + } +} + +static Boolean FunctionCallMightUseOrKillAnyAddressedVar(IROLinear *funccall) { + IROLinear *funcnd; + IROLinear *nd; + IROListNode *scan; + IROListNode *resultList; + ObjectList *olist; + ObjectList *killList; + VarRecord *var; + Boolean result; + Boolean foundObjRef; + Object *obj; + + result = 0; + + funcnd = funccall->u.funccall.linear8; + if (funcnd && copts.opt_pointer_analysis && funcnd->pointsToFunction && FunctionName) { + resultList = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, funcnd, &resultList); + + if (resultList) { + for (scan = resultList; scan; scan = scan->nextList) { + if (!scan->list.head || !scan->list.tail) { + result = 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(1592, obj != NULL); + + killList = NULL; + PointerAnalysis_GetFunctionKills(obj, funccall, &killList); + for (olist = killList; olist; olist = olist->next) { + if (!olist->object) { + result = 1; + } else { + var = IRO_FindVar(olist->object, 1, 1); + CError_ASSERT(1604, var != NULL); + if (var->xB) + result = 1; + } + + if (result) + break; + } + + while (killList) { + ObjectList *next = killList->next; + IRO_free(killList); + killList = next; + } + + if (!result) { + killList = NULL; + PointerAnalysis_GetFunctionDependencies(obj, funccall, &killList); + for (olist = killList; olist; olist = olist->next) { + if (!olist->object) { + result = 1; + } else { + var = IRO_FindVar(olist->object, 1, 1); + CError_ASSERT(1632, var != NULL); + if (var->xB) + result = 1; + } + + if (result) + break; + } + + while (killList) { + ObjectList *next = killList->next; + IRO_free(killList); + killList = next; + } + } + + if (result) + break; + } + } + + if (!foundObjRef) + result = 1; + if (result) + break; + } + + while (resultList) { + IROListNode *next = resultList->nextList; + IRO_free(resultList); + resultList = next; + } + } else { + result = 1; + } + } else { + result = 1; + } + + return result; +} + +static Boolean IndirectMightUseOrKillAnyAddressedVar(IROLinear *indirect) { + Boolean result; + IROLinear *inner; + IROLinear *nd; + IROListNode *scan; + IROListNode *resultList; + Boolean foundObjRef; + Object *obj; + VarRecord *var; + + result = 0; + + if ( + indirect && + indirect->type == IROLinearOp1Arg && + indirect->nodetype == EINDIRECT && + (inner = indirect->u.monadic) && + copts.opt_pointer_analysis && + inner->pointsToFunction && + FunctionName + ) { + resultList = NULL; + PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, inner, &resultList); + if (resultList) { + for (scan = resultList; scan; scan = scan->nextList) { + if (!scan->list.head || !scan->list.tail) { + result = 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(1723, obj != NULL); + var = IRO_FindVar(obj, 1, 1); + CError_ASSERT(1725, var != NULL); + + if (var->xB) + result = 1; + } + } + + if (!foundObjRef) + result = 1; + if (result) + break; + } + + while (resultList) { + IROListNode *next = resultList->nextList; + IRO_free(resultList); + resultList = next; + } + } else { + result = 1; + } + } else { + result = 1; + } + + return result; +} + +void IRO_ScalarizeClassDataMembers(void) { + IROLinear *nd; + VarRecord *var; + Boolean flag; + Object *obj; + IndirectRecord *irec; + IndirectRecordMatch *match; + IROLinear *tmp; + + nd = IRO_FirstLinear; + IRO_FirstIndirectRecord = NULL; + IRO_LastIndirectRecord = NULL; + RewriteIndDec(); + IRO_DumpAfterPhase("RewriteIndDec", 0); + flag = 0; + + while (nd) { + if (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT) { + CheckAddress(nd, &flag); + } + if (nd->type == IROLinearAsm) { + IAEffects effects; + SInt32 i; + CodeGen_GetAsmEffects(nd->u.asm_stmt, &effects); + for (i = 0; i < effects.numoperands; i++) { + if ((var = IRO_FindVar(effects.operands[i].object, 0, 1))) + CheckAddressConsistency(nd, var, -1, &stvoid); + else + CError_FATAL(1823); + } + } + if (nd->type == IROLinearFunccall && !flag) + flag = FunctionCallMightUseOrKillAnyAddressedVar(nd); + + nd = nd->next; + } + + if (flag) + DisableAddressedEntries(); + + for (irec = IRO_FirstIndirectRecord; irec; irec = irec->next) { + if (!(irec->flags & 1)) { + IROList list1; + IROList list2; + + obj = create_temp_object(irec->type); + var = IRO_FindVar(obj, 1, 1); + for (match = irec->matches; match; match = match->otherMatches) { + IRO_InitList(&list1); + IRO_InitList(&list2); + IRO_DuplicateExpr(match->nd, &list1); + IRO_DuplicateExpr(match->nd, &list2); + if (match->nd->type == IROLinearOperand && match->nd->u.node->type == EOBJREF) { + tmp = IRO_LocateFather(match->nd); + if (irec->flags & 2) { + tmp->flags |= IROLF_BitfieldIndirect; + var->x1A = match->nd->rtype; + var->x1E = list2.tail; + } + match->nd->u.node = create_objectrefnode(obj); + irec->x26 = list2.tail; + } else { + tmp = IRO_LocateFather(match->nd); + if (irec->flags & 2) { + tmp->flags |= IROLF_BitfieldIndirect; + var->x1A = match->nd->rtype; + var->x1E = list2.tail; + } + irec->x26 = list2.tail; + + IRO_NopOut(tmp->u.monadic); + tmp->u.monadic = IRO_NewLinear(IROLinearOperand); + tmp->u.monadic->u.node = create_objectrefnode(obj); + tmp->u.monadic->rtype = match->nd->rtype; + tmp->u.monadic->index = ++IRO_NumLinear; + tmp->u.monadic->flags |= IROLF_Ind | IROLF_Reffed; + IRO_NopOut(match->nd); + IRO_PasteAfter(tmp->u.monadic, tmp->u.monadic, match->nd); + } + } + + if (ObjectIsArg(irec->var->object)) { + IROLinear *op1; + IROLinear *op2; + IROLinear *op3; + IROLinear *op4; + IROLinear *op5; + + op1 = IRO_NewLinear(IROLinearOperand); + op1->u.node = create_objectrefnode(obj); + op1->rtype = op1->u.node->data.objref->type; + op1->index = ++IRO_NumLinear; + op1->flags |= IROLF_Ind | IROLF_Assigned; + + op2 = list1.tail; + + op3 = IRO_NewLinear(IROLinearOp1Arg); + op3->nodetype = EINDIRECT; + op3->rtype = irec->type; + op3->u.monadic = op1; + op3->index = ++IRO_NumLinear; + op3->flags |= IROLF_Assigned; + + op4 = IRO_NewLinear(IROLinearOp1Arg); + op4->nodetype = EINDIRECT; + op4->rtype = irec->type; + op4->u.monadic = op2; + op4->index = ++IRO_NumLinear; + op4->flags |= IROLF_Reffed; + + op5 = IRO_NewLinear(IROLinearOp2Arg); + op5->nodetype = EASS; + op5->u.diadic.left = op3; + op5->u.diadic.right = op4; + op5->rtype = irec->type; + op5->index = ++IRO_NumLinear; + + op2->next = op4; + op4->next = op1; + op1->next = op3; + op3->next = op5; + + IRO_PasteAfter(list1.head, op5, IRO_FirstLinear); + } + } + } + + IRO_CheckForUserBreak(); +} + +static Boolean CheckAddress(IROLinear *nd, Boolean *resultFlag) { + IROLinear *inner; + VarRecord *var; + Boolean result; + + inner = nd->u.monadic; + if (inner->type == IROLinearOp1Arg && inner->nodetype == EBITFIELD) + inner = inner->u.monadic; + + result = 0; + + if (inner->type == IROLinearOperand && inner->u.node->type == EOBJREF) { + if (IS_TYPE_CLASS(inner->u.node->data.objref->type) || IS_TYPE_STRUCT(inner->u.node->data.objref->type) || + IS_TYPE_ARRAY(inner->u.node->data.objref->type)) { + if (inner->u.node->data.objref->datatype == DLOCAL) { + var = IRO_FindVar(inner->u.node->data.objref, 0, 1); + CError_ASSERT(2240, var != NULL); + CheckAddressConsistency(nd, var, 0, nd->rtype); + result = 1; + } + } + } else if ( + inner->type == IROLinearOp2Arg && + inner->nodetype == EADD && + inner->u.diadic.left->type == IROLinearOperand && + inner->u.diadic.left->u.node->type == EOBJREF) { + if ( + inner->u.diadic.right->type == IROLinearOperand && + inner->u.diadic.right->u.node->type == EINTCONST && + inner->u.diadic.right->u.node->data.intval.hi == 0) { + if ( + IS_TYPE_CLASS(inner->u.diadic.left->u.node->data.objref->type) || + IS_TYPE_STRUCT(inner->u.diadic.left->u.node->data.objref->type) || + IS_TYPE_ARRAY(inner->u.diadic.left->u.node->data.objref->type) + ) { + if (inner->u.diadic.left->u.node->data.objref->datatype == DLOCAL) { + var = IRO_FindVar(inner->u.diadic.left->u.node->data.objref, 0, 1); + CError_ASSERT(2267, var != NULL); + CheckAddressConsistency(nd, var, inner->u.diadic.right->u.node->data.intval.lo, nd->rtype); + result = 1; + } + } + } else { + if ( + IS_TYPE_CLASS(inner->u.diadic.left->u.node->data.objref->type) || + IS_TYPE_STRUCT(inner->u.diadic.left->u.node->data.objref->type) || + IS_TYPE_ARRAY(inner->u.diadic.left->u.node->data.objref->type) + ) { + if (inner->u.diadic.left->u.node->data.objref->datatype == DLOCAL) { + var = IRO_FindVar(inner->u.diadic.left->u.node->data.objref, 0, 1); + CheckAddressConsistency(nd, var, -1, nd->rtype); + result = 1; + } + } + } + } + + if (!result && !*resultFlag) { + *resultFlag = IndirectMightUseOrKillAnyAddressedVar(nd); + } + + return 0; +} + +static Boolean CheckAddressConsistency(IROLinear *nd, VarRecord *var, SInt32 addend, Type *type) { + IndirectRecord *rp; + IndirectRecordMatch *match; + UInt32 flag; + IROLinear *inner; + UInt32 start_bit; + UInt32 end_bit; + + flag = 0; + inner = nd->u.monadic; + if (inner->type == IROLinearOp1Arg && inner->nodetype == EBITFIELD) { + start_bit = TYPE_BITFIELD(inner->rtype)->offset + 8 * addend; + end_bit = start_bit + TYPE_BITFIELD(inner->rtype)->bitlength - 1; + } else { + start_bit = 8 * addend; + end_bit = start_bit + 8 * type->size - 1; + } + + if (var->xB && !copts.opt_pointer_analysis) + return 0; + + if (nd->rtype && CParser_IsVolatile(nd->rtype, nd->nodeflags & ENODE_FLAG_QUALS)) + addend = -1; + if (is_volatile_object(var->object)) + addend = -1; + + for (rp = IRO_FirstIndirectRecord; rp; rp = rp->next) { + if (rp->var->index == var->index) { + if (rp->flags & 1) + return 0; + + if (addend == -1) { + flag = 1; + break; + } + + if (IRO_TypesEqual(rp->type, type) && rp->startbit == start_bit && rp->endbit == end_bit) { + match = oalloc(sizeof(IndirectRecordMatch)); + match->nd = inner; + match->otherMatches = NULL; + if (!rp->matches) { + rp->matches = match; + } else { + match->otherMatches = rp->matches; + rp->matches = match; + } + + IRO_Dump("Exact Match of Type and bits at %d and %d\n", rp->linear->index, nd->index); + IRO_Dump("Rp->startbit=%d,Rp->endbit=%d,start_bit=%d,end_bit=%d\n", rp->startbit, rp->endbit, start_bit, end_bit); + return 1; + } + + if (rp->startbit == start_bit && rp->endbit == end_bit && !IRO_TypesEqual(rp->type, type)) { + IRO_Dump("match on bits but mismatch on type %d and %d\n", rp->linear->index, nd->index); + IRO_Dump("Rp->startbit=%d,Rp->endbit=%d,start_bit=%d,end_bit=%d\n", rp->startbit, rp->endbit, start_bit, end_bit); + flag = 1; + break; + } + + if (rp->startbit >= start_bit && end_bit >= rp->startbit) { + IRO_Dump("Overlap detected --1 %d and %d\n", rp->linear->index, nd->index); + IRO_Dump("Rp->startbit=%d,Rp->endbit=%d,start_bit=%d,end_bit=%d\n", rp->startbit, rp->endbit, start_bit, end_bit); + flag = 1; + break; + } + + if (rp->startbit < start_bit && rp->endbit >= start_bit) { + IRO_Dump("Overlap detected --2 %d and %d\n", rp->linear->index, nd->index); + IRO_Dump("Rp->startbit=%d,Rp->endbit=%d,start_bit=%d,end_bit=%d\n", rp->startbit, rp->endbit, start_bit, end_bit); + flag = 1; + break; + } + } + } + + if (flag) { + DisableEntries(rp); + if (addend >= 0) + return 0; + } + + IRO_Dump("Create Entry at %d\n", nd->index); + IRO_Dump("start_bit=%d,end_bit=%d\n", start_bit, end_bit); + + rp = oalloc(sizeof(IndirectRecord)); + rp->linear = nd; + rp->flags = 0; + rp->var = var; + rp->addend = addend; + rp->size = type->size; + rp->type = type; + rp->next = NULL; + rp->matches = oalloc(sizeof(IndirectRecordMatch)); + rp->matches->nd = inner; + rp->matches->otherMatches = NULL; + rp->startbit = start_bit; + rp->endbit = end_bit; + + if (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT && + nd->u.monadic->type == IROLinearOp1Arg && nd->u.monadic->nodetype == EBITFIELD) + rp->flags |= 2; + + if (!(IS_TYPE_FLOAT(type) || IS_TYPE_INT(type) || IS_TYPE_POINTER_ONLY(type)) || + addend == -1 || ((inner->flags & IROLF_4000) && ObjectIsArg(var->object))) + rp->flags |= 1; + + if (IRO_FirstIndirectRecord) + IRO_LastIndirectRecord->next = rp; + else + IRO_FirstIndirectRecord = rp; + IRO_LastIndirectRecord = rp; + return 1; +} + +static void DisableEntries(IndirectRecord *irec) { + IndirectRecord *scan; + + for (scan = IRO_FirstIndirectRecord; scan; scan = scan->next) { + if (irec->var->index == scan->var->index) + scan->flags |= 1; + } +} + +static void DisableAddressedEntries(void) { + IndirectRecord *scan; + + for (scan = IRO_FirstIndirectRecord; scan; scan = scan->next) { + if (scan->var->xB) + scan->flags |= 1; + } +} + +static UInt32 ObjectIsArg(Object *obj) { + ObjectList *scan; + + for (scan = arguments; scan; scan = scan->next) { + if (scan->object == obj) + return 1; + } + + return 0; +} + diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroVars.h b/compiler_and_linker/FrontEnd/Optimizer/IroVars.h new file mode 100644 index 0000000..2af5b4d --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroVars.h @@ -0,0 +1,51 @@ +#ifndef COMPILER_IROVARS_H +#define COMPILER_IROVARS_H + +#include "IrOptimizer.h" +#include "compiler/enode.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +struct VarRecord { + UInt16 index; + Object *object; + int x6; + Boolean xA; + Boolean xB; + Boolean xC; + VarRecord *next; + IRODef *defs; + IROUse *uses; + Type *x1A; // bitfield-related + IROLinear *x1E; +}; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +extern VarRecord *IRO_FirstVar; +extern VarRecord *IRO_LastVar; +extern SInt32 IRO_NumVars; +extern Boolean IRO_IsBitField; +extern SInt32 IRO_BaseTerms; +extern SInt32 IRO_VarTerms; +extern Boolean IRO_IsModifyOp[MAXEXPR]; +extern Boolean IRO_IsAssignOp[MAXEXPR]; + +extern void IRO_InitializeIRO_IsModifyOpArray(void); +extern void IRO_InitializeIRO_IsAssignOpArray(void); +extern VarRecord *IRO_FindVar(Object *object, Boolean flag1, Boolean flag2); +extern void IRO_FindAllVars(void); +extern void IRO_ZapVarPtrs(void); +extern void IRO_UpdateVars(void); +extern void IRO_AddElmToList(IROLinear *linear, IROElmList **list); +extern void IRO_DecomposeAddressExpression(IROLinear *linear, IROAddrRecord *rec); +extern void IRO_DecomposeAddressExpression_Cheap(IROLinear *linear); +extern VarRecord *IRO_FindAssigned(IROLinear *linear); +extern void IRO_GetKills(IROLinear *linear); +extern void IRO_CheckInit(void); +extern void IRO_RewriteBitFieldTemps(void); +extern void IRO_ScalarizeClassDataMembers(void); + +#endif |