private static void ApplyOptimization(MethodInterpreter midRepresentation, int i, int j)
        {
            var localOps = midRepresentation.MidRepresentation.LocalOperations;

            var srcMethod  = PrecomputeRepeatedUtils.GetMethodData(localOps, i);
            var destMethod = PrecomputeRepeatedUtils.GetMethodData(localOps, j);

            if (srcMethod.Result == null)
            {
                return;
            }
            var computedType = srcMethod.Result.ComputedType();
            var newVreg      = midRepresentation.CreateCacheVariable(computedType);

            var assignedTo     = srcMethod.Result;
            var localOperation = PrecomputeRepeatedUtils.CreateAssignLocalOperation(assignedTo, newVreg);

            localOps.Insert(i + 1, localOperation);
            srcMethod.Result = newVreg;

            var destAssignment = PrecomputeRepeatedUtils.CreateAssignLocalOperation(destMethod.Result, newVreg);

            localOps.RemoveAt(j + 1);
            localOps.Insert(j + 1, destAssignment);
        }
        public override bool OptimizeBlock(MethodInterpreter midRepresentation, int startRange, int endRange,
                                           LocalOperation[] operations)
        {
            var localOperations = midRepresentation.MidRepresentation.LocalOperations;
            var calls           = FindCallsToPureFunctions(midRepresentation.MidRepresentation.UseDef, startRange, endRange);

            if (calls.Count < 2)
            {
                return(false);
            }
            for (var i = 0; i < calls.Count - 1; i++)
            {
                var firstMethodData = PrecomputeRepeatedUtils.GetMethodData(localOperations, calls, i);
                for (var j = i + 1; j < calls.Count; j++)
                {
                    var secondMethodData = PrecomputeRepeatedUtils.GetMethodData(localOperations, calls, j);
                    if (firstMethodData.Info != secondMethodData.Info)
                    {
                        continue;
                    }
                    var resultMerge = TryMergeCalls(i, j, firstMethodData, secondMethodData, localOperations);
                    if (!resultMerge)
                    {
                        continue;
                    }
                    ApplyOptimization(midRepresentation, calls[i], calls[j]);
                    return(true);
                }
            }
            return(false);
        }
        private static void ApplyOptimization(MethodInterpreter interpreter, int i, int j)
        {
            var localOps             = interpreter.MidRepresentation.LocalOperations;
            var firstOperator        = localOps[i].GetBinaryOperator();
            var secondOperator       = localOps[j].GetBinaryOperator();
            var newVreg              = interpreter.CreateCacheVariable(firstOperator.ComputedType());
            var assignLocalOperation = PrecomputeRepeatedUtils.CreateAssignLocalOperation(firstOperator.AssignedTo,
                                                                                          newVreg);

            localOps.Insert(i + 1, assignLocalOperation);

            firstOperator.AssignedTo = newVreg;

            var destAssignment = PrecomputeRepeatedUtils.CreateAssignLocalOperation(secondOperator.AssignedTo, newVreg);

            localOps.RemoveAt(j + 1);
            localOps.Insert(j + 1, destAssignment);
        }