/// <summary>
        /// Emits the specified platform instruction.
        /// </summary>
        /// <param name="node">The context.</param>
        /// <param name="emitter">The emitter.</param>
        protected override void Emit(InstructionNode node, MachineCodeEmitter emitter)
        {
            Debug.Assert(node.Result == node.Operand1, node.ToString());
            OpCode opCode = ComputeOpCode(node.Result, node.Operand1, node.Operand2);

            emitter.Emit(opCode, node.Result, node.Operand2);
        }
Exemple #2
0
        private void AssertEqualCodified(
            InstructionNode instruction,
            int expectedResult)
        {
            var number = Codifier.Codify(instruction);

            Assert.Equal(expectedResult, number);

            var uncodifiedInstruction = Codifier.UncodifyInstruction(number);

            Assert.Equal(instruction.ToString(), uncodifiedInstruction.ToString());
        }
        private void IfThenElse(InstructionNode node)
        {
            MainTrace?.Log(node.ToString());

            var result   = GetVariableState(node.Result);
            var operand1 = GetVariableState(node.Operand2);
            var operand2 = GetVariableState(node.Operand3);

            if (result.IsOverDefined)
            {
                return;
            }

            if (operand1.IsOverDefined || operand1.IsOverDefined)
            {
                UpdateToOverDefined(result);
            }
            else if (operand1.HasOnlyConstants && operand2.HasOnlyConstants)
            {
                foreach (var c in operand1.Constants)
                {
                    UpdateToConstant(result, c);

                    if (result.IsOverDefined)
                    {
                        return;
                    }
                }
                foreach (var c in operand2.Constants)
                {
                    UpdateToConstant(result, c);

                    if (result.IsOverDefined)
                    {
                        return;
                    }
                }
            }
            else if (operand1.IsUnknown || operand2.IsUnknown)
            {
                Debug.Assert(result.IsUnknown);
            }
            else
            {
                UpdateToOverDefined(result);
            }
        }
        /// <summary>
        /// Logs the instructions in the given enumerable to the trace.
        /// </summary>
        /// <param name="traceLog">The trace log.</param>
        /// <param name="node">The context.</param>
        private static void LogInstructions(TraceLog traceLog, InstructionNode node)
        {
            for (; !node.IsBlockEndInstruction; node = node.Next)
            {
                if (node.IsEmpty)
                {
                    continue;
                }

                traceLog.Log(node.ToString());

                if (node.IsBlockEndInstruction)
                {
                    return;
                }
            }
        }
        protected override void EmitInstruction(InstructionNode node, BaseCodeEmitter codeEmitter)
        {
            long start = codeEmitter.CurrentPosition;

            base.EmitInstruction(node, codeEmitter);

            long end = codeEmitter.CurrentPosition;

            var instruction = simAdapter.Convert(node, MethodCompiler.Method, BasicBlocks, (byte)(end - start));

            if (instruction != null)
            {
                stage.AddInstruction(symbol, start, instruction);
            }

            stage.AddSourceInformation(symbol, start, node.Offset.ToString() + "\t0x" + node.Offset.ToString("X") + "\t" + node.Block.ToString() + "\t" + symbol + "\t" + node.ToString());
        }
        /// <summary>
        /// Folds an integer operation on constants
        /// </summary>
        /// <param name="node">The node.</param>
        private void ConstantFoldingIntegerOperations(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.AddSigned || node.Instruction == IRInstruction.AddUnsigned ||
                  node.Instruction == IRInstruction.SubSigned || node.Instruction == IRInstruction.SubUnsigned ||
                  node.Instruction == IRInstruction.LogicalAnd || node.Instruction == IRInstruction.LogicalOr ||
                  node.Instruction == IRInstruction.LogicalXor ||
                  node.Instruction == IRInstruction.MulSigned || node.Instruction == IRInstruction.MulUnsigned ||
                  node.Instruction == IRInstruction.DivSigned || node.Instruction == IRInstruction.DivUnsigned ||
                  node.Instruction == IRInstruction.ArithmeticShiftRight ||
                  node.Instruction == IRInstruction.ShiftLeft || node.Instruction == IRInstruction.ShiftRight))
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            Operand result = node.Result;
            Operand op1 = node.Operand1;
            Operand op2 = node.Operand2;

            if (!op1.IsConstant || !op2.IsConstant)
                return;

            // Divide by zero!
            if ((node.Instruction == IRInstruction.DivSigned || node.Instruction == IRInstruction.DivUnsigned) && op2.IsConstant && op2.IsConstantZero)
                return;

            Operand constant = null;

            if (node.Instruction == IRInstruction.AddSigned || node.Instruction == IRInstruction.AddUnsigned)
            {
                constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger + op2.ConstantUnsignedLongInteger);
            }
            else if (node.Instruction == IRInstruction.SubSigned || node.Instruction == IRInstruction.SubUnsigned)
            {
                constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger - op2.ConstantUnsignedLongInteger);
            }
            else if (node.Instruction == IRInstruction.LogicalAnd)
            {
                constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger & op2.ConstantUnsignedLongInteger);
            }
            else if (node.Instruction == IRInstruction.LogicalOr)
            {
                constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger | op2.ConstantUnsignedLongInteger);
            }
            else if (node.Instruction == IRInstruction.LogicalXor)
            {
                constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger ^ op2.ConstantUnsignedLongInteger);
            }
            else if (node.Instruction == IRInstruction.MulSigned || node.Instruction == IRInstruction.MulUnsigned)
            {
                constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger * op2.ConstantUnsignedLongInteger);
            }
            else if (node.Instruction == IRInstruction.DivUnsigned)
            {
                constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger / op2.ConstantUnsignedLongInteger);
            }
            else if (node.Instruction == IRInstruction.DivSigned)
            {
                constant = Operand.CreateConstant(result.Type, op1.ConstantSignedLongInteger / op2.ConstantSignedLongInteger);
            }
            else if (node.Instruction == IRInstruction.ArithmeticShiftRight)
            {
                constant = Operand.CreateConstant(result.Type, ((long)op1.ConstantUnsignedLongInteger) >> (int)op2.ConstantUnsignedLongInteger);
            }
            else if (node.Instruction == IRInstruction.ShiftRight)
            {
                constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger >> (int)op2.ConstantUnsignedLongInteger);
            }
            else if (node.Instruction == IRInstruction.ShiftLeft)
            {
                constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger << (int)op2.ConstantUnsignedLongInteger);
            }

            if (constant == null)
                return;

            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("*** ConstantFoldingIntegerOperations");
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.SetInstruction(IRInstruction.Move, node.Result, constant);
            constantFoldingIntegerOperationsCount++;
            changeCount++;
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
        }
        private void ConstantFoldingAdditionAndSubstraction(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.AddSigned || node.Instruction == IRInstruction.AddUnsigned
                || node.Instruction == IRInstruction.SubSigned || node.Instruction == IRInstruction.SubUnsigned))
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            if (node.Result.Definitions.Count != 1)
                return;

            if (!node.Operand2.IsConstant)
                return;

            if (node.Result.Uses.Count != 1)
                return;

            var node2 = node.Result.Uses[0];

            if (!(node2.Instruction == IRInstruction.AddSigned || node2.Instruction == IRInstruction.AddUnsigned
                || node2.Instruction == IRInstruction.SubSigned || node2.Instruction == IRInstruction.SubUnsigned))
                return;

            if (!node2.Result.IsVirtualRegister)
                return;

            if (!node2.Operand2.IsConstant)
                return;

            Debug.Assert(node2.Result.Definitions.Count == 1);

            bool add = true;

            if ((node.Instruction == IRInstruction.AddSigned || node.Instruction == IRInstruction.AddUnsigned) &&
                (node2.Instruction == IRInstruction.SubSigned || node2.Instruction == IRInstruction.SubUnsigned))
            {
                add = false;
            }
            else if ((node.Instruction == IRInstruction.SubSigned || node.Instruction == IRInstruction.SubUnsigned) &&
                (node2.Instruction == IRInstruction.AddSigned || node2.Instruction == IRInstruction.AddUnsigned))
            {
                add = false;
            }

            ulong r = add ? node.Operand2.ConstantUnsignedLongInteger + node2.Operand2.ConstantUnsignedLongInteger :
                node.Operand2.ConstantUnsignedLongInteger - node2.Operand2.ConstantUnsignedLongInteger;

            Debug.Assert(node2.Result.Definitions.Count == 1);

            if (trace.Active) trace.Log("*** ConstantFoldingAdditionAndSubstraction");
            AddOperandUsageToWorkList(node2);
            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("BEFORE:\t" + node2.ToString());
            node2.SetInstruction(IRInstruction.Move, node2.Result, node.Result);
            if (trace.Active) trace.Log("AFTER: \t" + node2.ToString());
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.Operand2 = Operand.CreateConstant(node.Operand2.Type, r);
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
            constantFoldingAdditionAndSubstractionCount++;
            changeCount++;
        }
        /// <summary>
        /// Simplifies subtraction where both operands are the same
        /// </summary>
        /// <param name="node">The node.</param>
        private void ArithmeticSimplificationSubtraction(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.SubSigned || node.Instruction == IRInstruction.SubUnsigned))
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            Operand result = node.Result;
            Operand op1 = node.Operand1;
            Operand op2 = node.Operand2;

            if (op1 != op2)
                return;

            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("*** ArithmeticSimplificationSubtraction");
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.SetInstruction(IRInstruction.Move, result, Operand.CreateConstant(node.Result.Type, 0));
            arithmeticSimplificationSubtractionCount++;
            changeCount++;
        }
        /// <summary>
        /// Strength reduction for multiplication when one of the constants is zero or one
        /// </summary>
        /// <param name="node">The node.</param>
        private void ArithmeticSimplificationMultiplication(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.MulSigned || node.Instruction == IRInstruction.MulUnsigned))
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            if (!node.Operand2.IsConstant)
                return;

            Operand result = node.Result;
            Operand op1 = node.Operand1;
            Operand op2 = node.Operand2;

            if (op2.IsConstantZero)
            {
                AddOperandUsageToWorkList(node);
                if (trace.Active) trace.Log("*** ArithmeticSimplificationMultiplication");
                if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                node.SetInstruction(IRInstruction.Move, result, Operand.CreateConstant(node.Result.Type, 0));
                arithmeticSimplificationMultiplicationCount++;
                if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                changeCount++;
                return;
            }

            if (op2.IsConstantOne)
            {
                AddOperandUsageToWorkList(node);
                if (trace.Active) trace.Log("*** ArithmeticSimplificationMultiplication");
                if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                node.SetInstruction(IRInstruction.Move, result, op1);
                arithmeticSimplificationMultiplicationCount++;
                if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                changeCount++;
                return;
            }

            if (IsPowerOfTwo(op2.ConstantUnsignedLongInteger))
            {
                uint shift = GetPowerOfTwo(op2.ConstantUnsignedLongInteger);

                if (shift < 32)
                {
                    AddOperandUsageToWorkList(node);
                    if (trace.Active) trace.Log("*** ArithmeticSimplificationMultiplication");
                    if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                    node.SetInstruction(IRInstruction.ShiftLeft, result, op1, Operand.CreateConstant(TypeSystem, (int)shift));
                    arithmeticSimplificationMultiplicationCount++;
                    if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                    changeCount++;
                    return;
                }
            }
        }
        /// <summary>
        /// Strength reduction for integer addition when one of the constants is zero
        /// </summary>
        /// <param name="node">The node.</param>
        private void ArithmeticSimplificationAdditionAndSubstraction(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.AddSigned || node.Instruction == IRInstruction.AddUnsigned
                || node.Instruction == IRInstruction.SubSigned || node.Instruction == IRInstruction.SubUnsigned))
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            Operand result = node.Result;
            Operand op1 = node.Operand1;
            Operand op2 = node.Operand2;

            if (op2.IsConstant && !op1.IsConstant && op2.IsConstantZero)
            {
                AddOperandUsageToWorkList(node);
                if (trace.Active) trace.Log("*** ArithmeticSimplificationAdditionAndSubstraction");
                if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                node.SetInstruction(IRInstruction.Move, result, op1);
                if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                arithmeticSimplificationAdditionAndSubstractionCount++;
                changeCount++;
                return;
            }
        }
        /// <summary>
        /// Simplifies extended moves with a constant
        /// </summary>
        /// <param name="node">The node.</param>
        private void SimplifyExtendedMoveWithConstant(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.ZeroExtendedMove || node.Instruction == IRInstruction.SignExtendedMove))
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            if (node.Result.Definitions.Count != 1)
                return;

            if (!node.Operand1.IsConstant)
                return;

            Operand result = node.Result;
            Operand op1 = node.Operand1;

            Operand newOperand;

            if (node.Instruction == IRInstruction.ZeroExtendedMove && result.IsUnsigned && op1.IsSigned)
            {
                var newConstant = Unsign(op1.Type, op1.ConstantSignedLongInteger);
                newOperand = Operand.CreateConstant(node.Result.Type, newConstant);
            }
            else
            {
                newOperand = Operand.CreateConstant(node.Result.Type, op1.ConstantUnsignedLongInteger);
            }

            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("*** SimplifyExtendedMoveWithConstant");
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.SetInstruction(IRInstruction.Move, result, newOperand);
            simplifyExtendedMoveWithConstantCount++;
            changeCount++;
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
        }
        private void ConstantMoveToRight(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.AddSigned || node.Instruction == IRInstruction.AddUnsigned
                || node.Instruction == IRInstruction.MulSigned || node.Instruction == IRInstruction.MulUnsigned
                || node.Instruction == IRInstruction.LogicalAnd || node.Instruction == IRInstruction.LogicalOr
                || node.Instruction == IRInstruction.LogicalXor))
                return;

            if (node.Operand2.IsConstant)
                return;

            if (!node.Operand1.IsConstant)
                return;

            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("*** ConstantMoveToRight");
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            var op1 = node.Operand1;
            node.Operand1 = node.Operand2;
            node.Operand2 = op1;
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
            constantMoveToRightCount++;
            changeCount++;
        }
        /// <summary>
        /// Folds the constant phi instruction.
        /// </summary>
        /// <param name="node">The node.</param>
        private void ConstantFoldingPhi(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.Instruction != IRInstruction.Phi)
                return;

            if (node.Result.Definitions.Count != 1)
                return;

            if (!node.Result.IsInteger)
                return;

            Operand operand1 = node.Operand1;
            Operand result = node.Result;

            foreach (var operand in node.Operands)
            {
                if (!operand.IsConstant)
                    return;

                if (operand.ConstantUnsignedLongInteger != operand1.ConstantUnsignedLongInteger)
                    return;
            }

            if (trace.Active) trace.Log("*** FoldConstantPhiInstruction");
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            AddOperandUsageToWorkList(node);
            node.SetInstruction(IRInstruction.Move, result, operand1);
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
            constantFoldingPhiCount++;
            changeCount++;
        }
        private void RemoveUselessPhi(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.Instruction != IRInstruction.Phi)
                return;

            if (node.Result.Definitions.Count != 1)
                return;

            var result = node.Result;

            foreach (var use in node.Result.Uses)
            {
                if (use != node)
                    return;
            }

            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("REMOVED:\t" + node.ToString());
            node.SetInstruction(IRInstruction.Nop);
            removeUselessPhiCount++;
        }
        /// <summary>
        /// Arithmetics the simplification rem unsigned modulus.
        /// </summary>
        /// <param name="node">The node.</param>
        private void ArithmeticSimplificationRemUnsignedModulus(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.RemUnsigned))
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            if (!node.Operand2.IsConstant)
                return;

            if (node.Operand2.ConstantUnsignedLongInteger == 0)
                return;

            if (!IsPowerOfTwo(node.Operand2.ConstantUnsignedLongInteger))
                return;

            Operand result = node.Result;
            Operand op1 = node.Operand1;
            Operand op2 = node.Operand2;

            if (op2.ConstantUnsignedLongInteger == 0)
            {
                AddOperandUsageToWorkList(node);
                if (trace.Active) trace.Log("*** ArithmeticSimplificationRemUnsignedModulus");
                if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                node.SetInstruction(IRInstruction.Move, result, Operand.CreateConstant(TypeSystem, 0));
                arithmeticSimplificationModulus++;
                changeCount++;
                if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                return;
            }

            int power = GetPowerOfTwo(op2.ConstantUnsignedLongInteger);

            var mask = (1 << power) - 1;

            var constant = Operand.CreateConstant(TypeSystem, mask);

            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("*** ArithmeticSimplificationRemUnsignedModulus");
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.SetInstruction(IRInstruction.LogicalAnd, result, op1, constant);
            arithmeticSimplificationModulus++;
            changeCount++;
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
            return;
        }
        /// <summary>
        /// Arithmetics the simplification rem signed modulus.
        /// </summary>
        /// <param name="node">The node.</param>
        private void ArithmeticSimplificationRemSignedModulus(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.RemSigned))
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            if (!node.Operand2.IsConstant)
                return;

            if (node.Operand2.ConstantUnsignedLongInteger != 1)
                return;

            Operand result = node.Result;
            Operand op1 = node.Operand1;
            Operand op2 = node.Operand2;

            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("*** ArithmeticSimplificationRemSignedModulus");
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.SetInstruction(IRInstruction.Move, result, Operand.CreateConstant(TypeSystem, 0));
            arithmeticSimplificationModulus++;
            changeCount++;
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
            return;
        }
        private void ConstantFoldingDivision(InstructionNode node)
        {
            if (!(node.Instruction == IRInstruction.DivSigned || node.Instruction == IRInstruction.DivUnsigned))
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            if (node.Result.Definitions.Count != 1)
                return;

            if (!node.Operand2.IsResolvedConstant)
                return;

            if (node.Result.Uses.Count != 1)
                return;

            var node2 = node.Result.Uses[0];

            if (!(node2.Instruction == IRInstruction.DivSigned || node2.Instruction == IRInstruction.DivUnsigned))
                return;

            if (!node2.Result.IsVirtualRegister)
                return;

            if (!node2.Operand2.IsResolvedConstant)
                return;

            Debug.Assert(node2.Result.Definitions.Count == 1);

            ulong r = (node2.Instruction == IRInstruction.DivSigned) ?
                (ulong)(node.Operand2.ConstantSignedLongInteger / node2.Operand2.ConstantSignedLongInteger) :
                node.Operand2.ConstantUnsignedLongInteger / node2.Operand2.ConstantUnsignedLongInteger;

            if (trace.Active) trace.Log("*** ConstantFoldingDivision");
            AddOperandUsageToWorkList(node2);
            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("BEFORE:\t" + node2.ToString());
            node2.SetInstruction(IRInstruction.MoveInteger, node2.Result, node.Result);
            if (trace.Active) trace.Log("AFTER: \t" + node2.ToString());
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.Operand2 = Operand.CreateConstant(node.Operand2.Type, r);
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
            constantFoldingDivisionCount++;
            changeCount++;
        }
        /// <summary>
        /// Removes the useless move and dead code
        /// </summary>
        /// <param name="node">The node.</param>
        private void DeadCodeElimination(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.ResultCount != 1)
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            if (node.Result.Definitions.Count != 1)
                return;

            if (node.Instruction == IRInstruction.Call || node.Instruction == IRInstruction.IntrinsicMethodCall)
                return;

            if (node.Instruction == IRInstruction.Move && node.Operand1.IsVirtualRegister && node.Operand1 == node.Result)
            {
                if (trace.Active) trace.Log("*** DeadCodeElimination");
                if (trace.Active) trace.Log("REMOVED:\t" + node.ToString());
                AddOperandUsageToWorkList(node);
                node.SetInstruction(IRInstruction.Nop);
                instructionsRemovedCount++;
                deadCodeEliminationCount++;
                changeCount++;
                return;
            }

            if (node.Result.Uses.Count != 0)
                return;

            if (trace.Active) trace.Log("*** DeadCodeElimination");
            if (trace.Active) trace.Log("REMOVED:\t" + node.ToString());
            AddOperandUsageToWorkList(node);
            node.SetInstruction(IRInstruction.Nop);
            instructionsRemovedCount++;
            deadCodeEliminationCount++;
            changeCount++;
            return;
        }
        /// <summary>
        /// Simplifies the phi.
        /// </summary>
        /// <param name="node">The node.</param>
        private void SimplifyPhi(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.Instruction != IRInstruction.Phi)
                return;

            if (node.OperandCount != 1)
                return;

            if (node.Result.Definitions.Count != 1)
                return;

            if (trace.Active) trace.Log("*** SimplifyPhiInstruction");
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            AddOperandUsageToWorkList(node);
            node.SetInstruction(IRInstruction.Move, node.Result, node.Operand1);
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
            simplifyPhiCount++;
            changeCount++;
        }
        private void DeadCodeEliminationPhi(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.Instruction != IRInstruction.Phi)
                return;

            if (node.Result.Definitions.Count != 1)
                return;

            var result = node.Result;

            foreach (var use in result.Uses)
            {
                if (use != node)
                    return;
            }

            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("*** DeadCodeEliminationPhi");
            if (trace.Active) trace.Log("REMOVED:\t" + node.ToString());
            node.SetInstruction(IRInstruction.Nop);
            deadCodeEliminationPhi++;
            changeCount++;
        }
        /// <summary>
        /// Strength reduction for logical operators
        /// </summary>
        /// <param name="node">The node.</param>
        private void ArithmeticSimplificationLogicalOperators(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.LogicalAnd || node.Instruction == IRInstruction.LogicalOr))
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            if (!node.Operand2.IsConstant)
                return;

            Operand result = node.Result;
            Operand op1 = node.Operand1;
            Operand op2 = node.Operand2;

            if (node.Instruction == IRInstruction.LogicalOr)
            {
                if (op2.IsConstantZero)
                {
                    AddOperandUsageToWorkList(node);
                    if (trace.Active) trace.Log("*** ArithmeticSimplificationLogicalOperators");
                    if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                    node.SetInstruction(IRInstruction.Move, result, op1);
                    arithmeticSimplificationLogicalOperatorsCount++;
                    changeCount++;
                    if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                    return;
                }
            }
            else if (node.Instruction == IRInstruction.LogicalAnd)
            {
                if (op2.IsConstantZero)
                {
                    AddOperandUsageToWorkList(node);
                    if (trace.Active) trace.Log("*** ArithmeticSimplificationLogicalOperators");
                    if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                    node.SetInstruction(IRInstruction.Move, result, Operand.CreateConstant(node.Result.Type, 0));
                    arithmeticSimplificationLogicalOperatorsCount++;
                    changeCount++;
                    if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                    return;
                }

                if (((result.IsI4 || result.IsU4 || result.IsI || result.IsU) && op2.ConstantUnsignedInteger == 0xFFFFFFFF)
                    || ((result.IsI8 || result.IsU8) && op2.ConstantUnsignedLongInteger == 0xFFFFFFFFFFFFFFFF))
                {
                    AddOperandUsageToWorkList(node);
                    if (trace.Active) trace.Log("*** ArithmeticSimplificationLogicalOperators");
                    if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                    node.SetInstruction(IRInstruction.Move, result, op1);
                    arithmeticSimplificationLogicalOperatorsCount++;
                    changeCount++;
                    if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                    return;
                }
            }

            // TODO: Add more strength reductions especially for AND w/ 0xFF, 0xFFFF, 0xFFFFFFFF, etc when source or destination are same or smaller
        }
        /// <summary>
        /// Folds integer compare branch.
        /// </summary>
        /// <param name="node">The node.</param>
        private void FoldIntegerCompareBranch(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.Instruction != IRInstruction.IntegerCompareBranch)
                return;

            Debug.Assert(node.OperandCount == 2);

            Operand op1 = node.Operand1;
            Operand op2 = node.Operand2;

            if (!op1.IsConstant || !op2.IsConstant)
                return;

            Operand result = node.Result;
            InstructionNode nextNode = node.Next;

            if (nextNode.Instruction != IRInstruction.Jmp)
                return;

            if (node.BranchTargets[0] == nextNode.BranchTargets[0])
            {
                if (trace.Active) trace.Log("*** FoldIntegerCompareBranch-Useless");
                if (trace.Active) trace.Log("REMOVED:\t" + node.ToString());
                AddOperandUsageToWorkList(node);
                node.SetInstruction(IRInstruction.Nop);
                instructionsRemovedCount++;
                foldIntegerCompareBranchCount++;
                changeCount++;
                return;
            }

            bool compareResult = true;

            switch (node.ConditionCode)
            {
                case ConditionCode.Equal: compareResult = (op1.ConstantUnsignedLongInteger == op2.ConstantUnsignedLongInteger); break;
                case ConditionCode.NotEqual: compareResult = (op1.ConstantUnsignedLongInteger != op2.ConstantUnsignedLongInteger); break;
                case ConditionCode.GreaterOrEqual: compareResult = (op1.ConstantUnsignedLongInteger >= op2.ConstantUnsignedLongInteger); break;
                case ConditionCode.GreaterThan: compareResult = (op1.ConstantUnsignedLongInteger > op2.ConstantUnsignedLongInteger); break;
                case ConditionCode.LessOrEqual: compareResult = (op1.ConstantUnsignedLongInteger <= op2.ConstantUnsignedLongInteger); break;
                case ConditionCode.LessThan: compareResult = (op1.ConstantUnsignedLongInteger < op2.ConstantUnsignedLongInteger); break;

                // TODO: Add more
                default: return;
            }

            BasicBlock notTaken;
            InstructionNode notUsed;

            if (trace.Active) trace.Log("*** FoldIntegerCompareBranch");

            if (compareResult)
            {
                notTaken = nextNode.BranchTargets[0];
                if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                node.SetInstruction(IRInstruction.Jmp, node.BranchTargets[0]);
                if (trace.Active) trace.Log("AFTER:\t" + node.ToString());

                notUsed = nextNode;
            }
            else
            {
                notTaken = node.BranchTargets[0];
                notUsed = node;
            }

            if (trace.Active) trace.Log("REMOVED:\t" + node.ToString());
            AddOperandUsageToWorkList(notUsed);
            notUsed.SetInstruction(IRInstruction.Nop);
            instructionsRemovedCount++;
            foldIntegerCompareBranchCount++;
            changeCount++;

            // if target block no longer has any predecessors (or the only predecessor is itself), remove all instructions from it.
            CheckAndClearEmptyBlock(notTaken);
        }
        /// <summary>
        /// Strength reduction shift operators.
        /// </summary>
        /// <param name="node">The node.</param>
        private void ArithmeticSimplificationShiftOperators(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.ShiftLeft || node.Instruction == IRInstruction.ShiftRight || node.Instruction == IRInstruction.ArithmeticShiftRight))
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            if (!node.Operand2.IsConstant)
                return;

            Operand result = node.Result;
            Operand op1 = node.Operand1;
            Operand op2 = node.Operand2;

            if (op2.IsConstantZero || op1.IsConstantZero)
            {
                AddOperandUsageToWorkList(node);
                if (trace.Active) trace.Log("*** ArithmeticSimplificationShiftOperators");
                if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                node.SetInstruction(IRInstruction.Move, result, op1);
                arithmeticSimplificationShiftOperators++;
                changeCount++;
                if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                return;
            }
        }
        private void FoldLoadStoreOffsets(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.Load || node.Instruction == IRInstruction.Store
                || node.Instruction == IRInstruction.LoadSignExtended || node.Instruction == IRInstruction.LoadZeroExtended))
                return;

            if (!node.Operand2.IsConstant)
                return;

            if (!node.Operand1.IsVirtualRegister)
                return;

            if (node.Operand1.Uses.Count != 1)
                return;

            var node2 = node.Operand1.Definitions[0];

            if (!(node2.Instruction == IRInstruction.AddSigned || node2.Instruction == IRInstruction.SubSigned ||
                node2.Instruction == IRInstruction.AddUnsigned || node2.Instruction == IRInstruction.SubUnsigned))
                return;

            if (!node2.Operand2.IsConstant)
                return;

            Operand constant;

            if (node2.Instruction == IRInstruction.AddUnsigned || node2.Instruction == IRInstruction.AddSigned)
            {
                constant = Operand.CreateConstant(node.Operand2.Type, node2.Operand2.ConstantSignedLongInteger + node.Operand2.ConstantSignedLongInteger);
            }
            else
            {
                constant = Operand.CreateConstant(node.Operand2.Type, node.Operand2.ConstantSignedLongInteger - node2.Operand2.ConstantSignedLongInteger);
            }

            if (trace.Active) trace.Log("*** FoldLoadStoreOffsets");
            AddOperandUsageToWorkList(node);
            AddOperandUsageToWorkList(node2);
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.Operand1 = node2.Operand1;
            node.Operand2 = constant;
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
            if (trace.Active) trace.Log("REMOVED:\t" + node2.ToString());
            node2.SetInstruction(IRInstruction.Nop);
            foldLoadStoreOffsetsCount++;
            instructionsRemovedCount++;
            changeCount++;
        }
        private void CombineIntegerCompareBranch(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.Instruction != IRInstruction.IntegerCompareBranch)
                return;

            if (!(node.ConditionCode == ConditionCode.NotEqual || node.ConditionCode == ConditionCode.Equal))
                return;

            if (!((node.Operand1.IsVirtualRegister && node.Operand2.IsConstant && node.Operand2.IsConstantZero) ||
                (node.Operand2.IsVirtualRegister && node.Operand1.IsConstant && node.Operand1.IsConstantZero)))
                return;

            var operand = (node.Operand2.IsConstant && node.Operand2.IsConstantZero) ? node.Operand1 : node.Operand2;

            if (operand.Uses.Count != 1)
                return;

            if (operand.Definitions.Count != 1)
                return;

            var node2 = operand.Definitions[0];

            if (node2.Instruction != IRInstruction.IntegerCompare)
                return;

            AddOperandUsageToWorkList(node2);
            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("*** CombineIntegerCompareBranch");
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.ConditionCode = node.ConditionCode == ConditionCode.NotEqual ? node2.ConditionCode : node2.ConditionCode.GetOpposite();
            node.Operand1 = node2.Operand1;
            node.Operand2 = node2.Operand2;
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
            if (trace.Active) trace.Log("REMOVED:\t" + node2.ToString());
            node2.SetInstruction(IRInstruction.Nop);
            combineIntegerCompareBranchCount++;
            instructionsRemovedCount++;
            changeCount++;
        }
        private void NormalizeConstantTo32Bit(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.ResultCount != 1)
                return;

            if (!node.Result.IsInt)
                return;

            if (node.Instruction == IRInstruction.LogicalAnd ||
                node.Instruction == IRInstruction.LogicalOr ||
                node.Instruction == IRInstruction.LogicalXor ||
                node.Instruction == IRInstruction.LogicalNot)
            {
                if (node.Operand1.IsConstant && node.Operand1.IsLong)
                {
                    if (trace.Active) trace.Log("*** NormalizeConstantTo32Bit");

                    if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                    node.Operand1 = Operand.CreateConstant(TypeSystem, (int)(node.Operand1.ConstantUnsignedLongInteger & uint.MaxValue));
                    changeCount++;
                    if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                    AddOperandUsageToWorkList(node);
                }
                if (node.OperandCount >= 2 && node.Operand2.IsConstant && node.Operand2.IsLong)
                {
                    if (trace.Active) trace.Log("*** NormalizeConstantTo32Bit");

                    if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                    node.Operand2 = Operand.CreateConstant(TypeSystem, (int)(node.Operand2.ConstantUnsignedLongInteger & uint.MaxValue));
                    changeCount++;
                    if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                    AddOperandUsageToWorkList(node);
                }
            }
        }
        /// <summary>
        /// Folds the integer compare on constants
        /// </summary>
        /// <param name="node">The node.</param>
        private void ConstantFoldingIntegerCompare(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.Instruction != IRInstruction.IntegerCompare)
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            Operand result = node.Result;
            Operand op1 = node.Operand1;
            Operand op2 = node.Operand2;

            if (!op1.IsConstant || !op2.IsConstant)
                return;

            if (!op1.IsValueType || !op2.IsValueType)
                return;

            bool compareResult = true;

            switch (node.ConditionCode)
            {
                case ConditionCode.Equal: compareResult = (op1.ConstantUnsignedLongInteger == op2.ConstantUnsignedLongInteger); break;
                case ConditionCode.NotEqual: compareResult = (op1.ConstantUnsignedLongInteger != op2.ConstantUnsignedLongInteger); break;
                case ConditionCode.GreaterOrEqual: compareResult = (op1.ConstantUnsignedLongInteger >= op2.ConstantUnsignedLongInteger); break;
                case ConditionCode.GreaterThan: compareResult = (op1.ConstantUnsignedLongInteger > op2.ConstantUnsignedLongInteger); break;
                case ConditionCode.LessOrEqual: compareResult = (op1.ConstantUnsignedLongInteger <= op2.ConstantUnsignedLongInteger); break;
                case ConditionCode.LessThan: compareResult = (op1.ConstantUnsignedLongInteger < op2.ConstantUnsignedLongInteger); break;

                // TODO: Add more
                default: return;
            }

            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("*** ConstantFoldingIntegerCompare");
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.SetInstruction(IRInstruction.Move, result, Operand.CreateConstant(result.Type, compareResult ? 1 : 0));
            constantFoldingIntegerCompareCount++;
            changeCount++;
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
        }
        private void ReduceZeroExtendedMove(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.Instruction != IRInstruction.ZeroExtendedMove)
                return;

            if (!node.Operand1.IsVirtualRegister)
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            if (trace.Active) trace.Log("*** ReduceZeroExtendedMove");
            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.SetInstruction(IRInstruction.Move, node.Result, node.Operand1);
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
            reduceZeroExtendedMoveCount++;
            changeCount++;
        }
        private void ConstantFoldingLogicalOr(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.Instruction != IRInstruction.LogicalOr)
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            if (node.Result.Definitions.Count != 1)
                return;

            if (!node.Operand2.IsConstant)
                return;

            if (node.Result.Uses.Count != 1)
                return;

            var node2 = node.Result.Uses[0];

            if (node2.Instruction != IRInstruction.LogicalOr)
                return;

            if (!node2.Result.IsVirtualRegister)
                return;

            if (!node2.Operand2.IsConstant)
                return;

            Debug.Assert(node2.Result.Definitions.Count == 1);

            ulong r = node.Operand2.ConstantUnsignedLongInteger | node2.Operand2.ConstantUnsignedLongInteger;

            if (trace.Active) trace.Log("*** ConstantFoldingLogicalOr");
            AddOperandUsageToWorkList(node2);
            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("BEFORE:\t" + node2.ToString());
            node2.SetInstruction(IRInstruction.Move, node2.Result, node.Result);
            if (trace.Active) trace.Log("AFTER: \t" + node2.ToString());
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.Operand2 = Operand.CreateConstant(node.Operand2.Type, r);
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
            constantFoldingLogicalOrCount++;
            changeCount++;
        }
        /// <summary>
        /// Removes the unless integer compare branch.
        /// </summary>
        /// <param name="node">The node.</param>
        private void RemoveUselessIntegerCompareBranch(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.Instruction != IRInstruction.IntegerCompareBranch)
                return;

            if (node.Block.NextBlocks.Count != 1)
                return;

            if (trace.Active) trace.Log("REMOVED:\t" + node.ToString());
            AddOperandUsageToWorkList(node);
            node.SetInstruction(IRInstruction.Nop);
            instructionsRemovedCount++;
            removeUselessIntegerCompareBranch++;
            changeCount++;
        }
        /// <summary>
        /// Simple copy propagation.
        /// </summary>
        /// <param name="node">The node.</param>
        private void SimpleForwardCopyPropagation(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (node.Instruction != IRInstruction.Move)
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            if (node.Result.Definitions.Count != 1)
                return;

            if (node.Operand1.Definitions.Count != 1)
                return;

            if (node.Operand1.IsConstant)
                return;

            if (!node.Operand1.IsVirtualRegister)
                return;

            // If the pointer or reference types are different, we can not copy propagation because type information would be lost.
            // Also if the operand sign is different, we cannot do it as it requires a signed/unsigned extended move, not a normal move
            if (!CanCopyPropagation(node.Result, node.Operand1))
                return;

            Operand destination = node.Result;
            Operand source = node.Operand1;

            if (ContainsAddressOf(destination))
                return;

            // for each statement T that uses operand, substituted c in statement T
            AddOperandUsageToWorkList(node);

            foreach (var useNode in destination.Uses.ToArray())
            {
                for (int i = 0; i < useNode.OperandCount; i++)
                {
                    var operand = useNode.GetOperand(i);

                    if (destination == operand)
                    {
                        if (trace.Active) trace.Log("*** SimpleForwardCopyPropagation");
                        if (trace.Active) trace.Log("BEFORE:\t" + useNode.ToString());
                        useNode.SetOperand(i, source);
                        simpleForwardCopyPropagationCount++;
                        changeCount++;
                        if (trace.Active) trace.Log("AFTER: \t" + useNode.ToString());
                    }
                }
            }

            Debug.Assert(destination.Uses.Count == 0);

            if (trace.Active) trace.Log("REMOVED:\t" + node.ToString());
            AddOperandUsageToWorkList(node);
            node.SetInstruction(IRInstruction.Nop);
            instructionsRemovedCount++;
            changeCount++;
        }
        /// <summary>
        /// Simplifies sign/zero extended move
        /// </summary>
        /// <param name="node">The node.</param>
        private void SimplifyExtendedMove(InstructionNode node)
        {
            if (node.IsEmpty)
                return;

            if (!(node.Instruction == IRInstruction.ZeroExtendedMove || node.Instruction == IRInstruction.SignExtendedMove))
                return;

            if (!node.Result.IsVirtualRegister || !node.Operand1.IsVirtualRegister)
                return;

            if (!((NativePointerSize == 4 && node.Result.IsInt && (node.Operand1.IsInt || node.Operand1.IsU || node.Operand1.IsI)) ||
                (NativePointerSize == 4 && node.Operand1.IsInt && (node.Result.IsInt || node.Result.IsU || node.Result.IsI)) ||
                (NativePointerSize == 8 && node.Result.IsLong && (node.Operand1.IsLong || node.Operand1.IsU || node.Operand1.IsI)) ||
                (NativePointerSize == 8 && node.Operand1.IsLong && (node.Result.IsLong || node.Result.IsU || node.Result.IsI))))
                return;

            AddOperandUsageToWorkList(node);
            if (trace.Active) trace.Log("*** SimplifyExtendedMove");
            if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
            node.SetInstruction(IRInstruction.Move, node.Result, node.Operand1);
            simplifyExtendedMoveCount++;
            if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
            changeCount++;
        }
        private void Phi(InstructionNode node)
        {
            MainTrace?.Log(node.ToString());

            var result = GetVariableState(node.Result);

            if (result.IsOverDefined)
            {
                return;
            }

            var sourceBlocks = node.PhiBlocks;
            var currentBlock = node.Block;

            MainTrace?.Log($"Loop: {currentBlock.PreviousBlocks.Count}");

            for (var index = 0; index < currentBlock.PreviousBlocks.Count; index++)
            {
                var predecessor = sourceBlocks[index];

                phiStatements.AddIfNew(predecessor, node);

                bool executable = blockStates[predecessor.Sequence];

                MainTrace?.Log($"# {index}: {predecessor} {(executable ? "Yes" : "No")}");

                if (!executable)
                {
                    continue;
                }

                if (result.IsOverDefined)
                {
                    continue;
                }

                var op = node.GetOperand(index);

                var operand = GetVariableState(op);

                MainTrace?.Log($"# {index}: {operand}");

                CheckAndUpdateNullAssignment(result, operand);

                if (operand.IsOverDefined)
                {
                    UpdateToOverDefined(result);
                    continue;
                }
                else if (operand.IsSingleConstant)
                {
                    UpdateToConstant(result, operand.ConstantUnsignedLongInteger);
                    continue;
                }
                else if (operand.HasMultipleConstants)
                {
                    foreach (var c in operand.Constants)
                    {
                        UpdateToConstant(result, c);

                        if (result.IsOverDefined)
                        {
                            break;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Strength reduction for division when one of the constants is zero or one
        /// </summary>
        /// <param name="node">The node.</param>
        private void ArithmeticSimplificationDivision(InstructionNode node)
        {
            if (!(node.Instruction == IRInstruction.DivSigned || node.Instruction == IRInstruction.DivUnsigned))
                return;

            if (!node.Result.IsVirtualRegister)
                return;

            Operand result = node.Result;
            Operand op1 = node.Operand1;
            Operand op2 = node.Operand2;

            if (!op2.IsResolvedConstant || op2.IsConstantZero)
            {
                // Possible divide by zero
                return;
            }

            if (op1.IsResolvedConstant && op1.IsConstantZero)
            {
                AddOperandUsageToWorkList(node);
                if (trace.Active) trace.Log("*** ArithmeticSimplificationDivision");
                if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                node.SetInstruction(IRInstruction.MoveInteger, result, ConstantZero);
                arithmeticSimplificationDivisionCount++;
                changeCount++;
                if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                return;
            }

            if (op2.IsResolvedConstant && op2.IsConstantOne)
            {
                AddOperandUsageToWorkList(node);
                if (trace.Active) trace.Log("*** ArithmeticSimplificationDivision");
                if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                node.SetInstruction(IRInstruction.MoveInteger, result, op1);
                arithmeticSimplificationDivisionCount++;
                changeCount++;
                if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                return;
            }

            if (node.Instruction == IRInstruction.DivUnsigned && IsPowerOfTwo(op2.ConstantUnsignedLongInteger))
            {
                int shift = GetPowerOfTwo(op2.ConstantUnsignedLongInteger);

                if (shift < 32)
                {
                    AddOperandUsageToWorkList(node);
                    if (trace.Active) trace.Log("*** ArithmeticSimplificationDivision");
                    if (trace.Active) trace.Log("BEFORE:\t" + node.ToString());
                    node.SetInstruction(IRInstruction.ShiftRight, result, op1, Operand.CreateConstant(TypeSystem, (int)shift));
                    arithmeticSimplificationDivisionCount++;
                    changeCount++;
                    if (trace.Active) trace.Log("AFTER: \t" + node.ToString());
                    return;
                }
            }
        }