From 094b96ca1df4a035b5f93c351f773306c0241f3f Mon Sep 17 00:00:00 2001
From: Ash Wolf <ninji@wuffs.org>
Date: Thu, 26 Jan 2023 11:30:47 +0000
Subject: move lots of source files around to match their actual placement in
 the original tree

---
 compiler_and_linker/FrontEnd/Optimizer/BitVector.h |   36 +
 compiler_and_linker/FrontEnd/Optimizer/IROUseDef.c | 1432 +++++
 compiler_and_linker/FrontEnd/Optimizer/IROUseDef.h |   48 +
 .../FrontEnd/Optimizer/IrOptimizer.c               |  400 ++
 .../FrontEnd/Optimizer/IrOptimizer.h               |   30 +
 .../FrontEnd/Optimizer/IroBitVect.c                |  112 +
 compiler_and_linker/FrontEnd/Optimizer/IroCSE.c    | 1038 ++++
 compiler_and_linker/FrontEnd/Optimizer/IroCSE.h    |   45 +
 compiler_and_linker/FrontEnd/Optimizer/IroDump.c   |  660 +++
 compiler_and_linker/FrontEnd/Optimizer/IroDump.h   |   27 +
 .../FrontEnd/Optimizer/IroEmptyLoop.c              |  560 ++
 .../FrontEnd/Optimizer/IroEmptyLoop.h              |    8 +
 compiler_and_linker/FrontEnd/Optimizer/IroEval.c   |  914 ++++
 compiler_and_linker/FrontEnd/Optimizer/IroEval.h   |   14 +
 .../FrontEnd/Optimizer/IroExprRegeneration.c       | 1531 ++++++
 .../FrontEnd/Optimizer/IroExprRegeneration.h       |    8 +
 .../FrontEnd/Optimizer/IroFlowgraph.c              |  439 ++
 .../FrontEnd/Optimizer/IroFlowgraph.h              |   97 +
 compiler_and_linker/FrontEnd/Optimizer/IroJump.c   |  267 +
 compiler_and_linker/FrontEnd/Optimizer/IroJump.h   |   12 +
 .../FrontEnd/Optimizer/IroLinearForm.c             | 1797 ++++++
 .../FrontEnd/Optimizer/IroLinearForm.h             |  165 +
 compiler_and_linker/FrontEnd/Optimizer/IroLoop.c   | 2324 ++++++++
 compiler_and_linker/FrontEnd/Optimizer/IroLoop.h   |  111 +
 compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c |  564 ++
 compiler_and_linker/FrontEnd/Optimizer/IroMalloc.h |   15 +
 .../FrontEnd/Optimizer/IroPointerAnalysis.c        | 5734 ++++++++++++++++++++
 .../FrontEnd/Optimizer/IroPointerAnalysis.h        |   25 +
 .../FrontEnd/Optimizer/IroPointerAnalysisADTs.c    | 2736 ++++++++++
 .../FrontEnd/Optimizer/IroPropagate.c              |  593 ++
 .../FrontEnd/Optimizer/IroPropagate.h              |   35 +
 .../FrontEnd/Optimizer/IroRangePropagation.c       |  774 +++
 .../FrontEnd/Optimizer/IroRangePropagation.h       |    8 +
 .../FrontEnd/Optimizer/IroSubable.c                |  160 +
 .../FrontEnd/Optimizer/IroSubable.h                |   10 +
 .../FrontEnd/Optimizer/IroTransform.c              | 2794 ++++++++++
 .../FrontEnd/Optimizer/IroTransform.h              |   13 +
 .../FrontEnd/Optimizer/IroUnrollLoop.c             | 2305 ++++++++
 .../FrontEnd/Optimizer/IroUnrollLoop.h             |   23 +
 compiler_and_linker/FrontEnd/Optimizer/IroUtil.c   | 1262 +++++
 compiler_and_linker/FrontEnd/Optimizer/IroUtil.h   |  127 +
 compiler_and_linker/FrontEnd/Optimizer/IroVars.c   | 1430 +++++
 compiler_and_linker/FrontEnd/Optimizer/IroVars.h   |   51 +
 43 files changed, 30734 insertions(+)
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/BitVector.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IROUseDef.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IROUseDef.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroBitVect.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroCSE.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroCSE.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroDump.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroDump.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroEval.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroEval.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroJump.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroJump.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroLoop.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroLoop.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroMalloc.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysisADTs.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroPropagate.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroSubable.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroSubable.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroTransform.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroTransform.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroUtil.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroUtil.h
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroVars.c
 create mode 100644 compiler_and_linker/FrontEnd/Optimizer/IroVars.h

(limited to 'compiler_and_linker/FrontEnd/Optimizer')

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(&copy1, r13, sizeof(IROLinear));
+    memcpy(&copy2, 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, &copy1, 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, &copy2, 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(&copy3, fnode->first, sizeof(IROLinear));
+        memcpy(fnode->first, &copy2, 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(&params, 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, &params);
+        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(&params, 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, &params);
+        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(&params, 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, &params);
+        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(&params, 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, &params);
+        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(&params, 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, &params);
+
+    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(&params, 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, &params);
+
+    if (var && !params.x10) {
+        ExtendedParam_sub_4867B0(ep, var);
+        FillInAppropriateMappingsWithExtParamAction(var, &params);
+    }
+
+    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(&params, 0, sizeof(params));
+    params.proc = proc;
+    params.ptfCopy = ptfCopy;
+    params.mapCopy = mapCopy;
+    params.stackPtr = &stCallingContextStack;
+
+    PointsToFunction_ForEach(initial, MatchPTFAction1, &params);
+    PointsToFunction_ForEach(initial, MatchPTFAction2, &params);
+
+    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(&params, 0, sizeof(params));
+    params.toBeRemoved = toBeRemoved;
+    params.toBeAdded = toBeAdded;
+    params.stackPtr = stackPtr;
+    params.map = map;
+    params.x10 = 0;
+
+    LocationSetSet_ForEach(thingsPointedTo, ExpandLocationSetSetToActualsAction, &params);
+
+    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(&params, 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, &params);
+                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(&params, 0, sizeof(params));
+        params.last = NULL;
+        do {
+            params.lowest = NULL;
+            pmf_sub_487C70(map, CreateExtendedParamAction, &params);
+            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(&params, 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, &params);
+        PointsToFunction_ForEach(params.toBeKilled, KillLocationsAction, &params);
+    }
+
+    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(&params, 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, &params);
+                PointsToFunction_ForEach(params.toBeKilled, KillLocationsAction, &params);
+            }
+
+            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(&params, 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, &params);
+        }
+    }
+
+    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(&params, 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, &params);
+
+    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(&params, 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(&params2, 0, sizeof(params2));
+                        params2.x0 = *((CInt64 *) PAMemoryBlock_thing(block));
+                        IRO_TruncateValueToType(&params2.x0, nd->u.diadic.right->rtype);
+                        params2.nd = nd;
+                        params2.xC = 0;
+
+                        if (!CInt64_IsZero(&params2.x0)) {
+                            LocationSetSet_ForEach(params.srcs, EvalAssignAction2, &params2);
+                            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(&params2, 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(&params2.x0, type->size);
+
+                if (!CInt64_IsZero(&params2.x0)) {
+                    LocationSetSet_ForEach(params.srcs, EvalAssignAction2, &params2);
+                    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, &params);
+
+        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(&params, 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, &params);
+            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(&params, 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, &params);
+
+        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(&params, 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, &params);
+
+        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(&params, 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, &params);
+                result |= params.x10;
+            }
+            result |= EvalMeet(proc, fnode, Int, ptf);
+            pointsToFunc = Int->pointsToFunction;
+            x18 = 0;
+        } else if (!Int->pointsToFunction) {
+            if (pointsToFunc)
+                AssignEachInPointsToFunction(pointsToFunc, &params);
+            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(&params, 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, &params);
+        }
+    }
+}
+
+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(&params, 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, &params);
+        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(&params, 0, sizeof(params));
+    params.x8 = 0;
+    params.x0 = lss2;
+    LocationSetSet_ForEach(lss1, FindAliasingAction, &params);
+
+    if (!params.x8) {
+        params.x0 = lss1;
+        LocationSetSet_ForEach(lss2, FindAliasingAction, &params);
+
+        if (!params.x8) {
+            RemoveRestrictedExtendedParams(lss1);
+            RemoveRestrictedExtendedParams(lss2);
+            ExpandLocationSetSetToActuals(&stCallingContextStack, NULL, lss1);
+            ExpandLocationSetSetToActuals(&stCallingContextStack, NULL, lss2);
+
+            params.x0 = lss2;
+            LocationSetSet_ForEach(lss1, FindAliasingAction, &params);
+
+            if (!params.x8) {
+                params.x0 = lss1;
+                LocationSetSet_ForEach(lss2, FindAliasingAction, &params);
+            }
+        }
+    }
+
+    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(&params, 0, sizeof(params));
+    params.x8 = 0;
+    params.x0 = lss2;
+    LocationSetSet_ForEach(lss1, FindAliasingAction, &params);
+
+    if (!params.x8) {
+        params.x0 = lss1;
+        LocationSetSet_ForEach(lss2, FindAliasingAction, &params);
+
+        if (!params.x8) {
+            RemoveRestrictedExtendedParams(lss1);
+            RemoveRestrictedExtendedParams(lss2);
+            ExpandLocationSetSetToActuals(&stCallingContextStack, NULL, lss1);
+            ExpandLocationSetSetToActuals(&stCallingContextStack, NULL, lss2);
+
+            params.x0 = lss2;
+            LocationSetSet_ForEach(lss1, FindAliasingAction, &params);
+
+            if (!params.x8) {
+                params.x0 = lss1;
+                LocationSetSet_ForEach(lss2, FindAliasingAction, &params);
+            }
+        }
+    }
+
+    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(&params, 0, sizeof(params));
+        params.proc = proc;
+        params.indirectType = indirect->rtype;
+        params.list = list;
+
+        LocationSetSet_ForEach(set, LookupLinearExprAction, &params);
+        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(&params, 0, sizeof(params));
+        params.proc = proc;
+        params.indirectType = indirect->rtype;
+        params.list = list;
+
+        LocationSetSet_ForEach(set, LookupENodeExprAction, &params);
+        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(&params, 0, sizeof(params));
+        params.proc = proc;
+        params.indirectType = var->object->type;
+        params.list = list;
+
+        LocationSetSet_ForEach(set, LookupLinearExprAction, &params);
+        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(&params, 0, sizeof(params));
+        params.proc = proc;
+        params.indirectType = var->object->type;
+        params.list = list;
+
+        LocationSetSet_ForEach(set, LookupENodeExprAction, &params);
+        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(&params, 0, sizeof(params));
+            params.proc = proc;
+            params.ptf = ptf;
+            params.funccall = funccall;
+            params.map = NULL;
+            params.list = list;
+            LocationSetSet_ForEach(set, GetFunctionDepsOrKillsAction, &params);
+        }
+    }
+
+    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(&params, 0, sizeof(params));
+            params.proc = proc;
+            params.ptf = ptf;
+            params.funccall = funccall;
+            params.map = map;
+            params.list = list;
+            PointsToFunction_ForEach(finalPointsTo, GetFunctionDepsOrKillsAction2, &params);
+        }
+        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
-- 
cgit v1.2.3