예제 #1
0
        protected virtual AstNode _Optimize(AstNodeExprBinop binary)
        {
            //Console.WriteLine("Optimize.AstNodeExprBinop: {0} {1} {2}", Binary.LeftNode, Binary.Operator, Binary.RightNode);
            var leftImm   = binary.LeftNode as AstNodeExprImm;
            var rightImm  = binary.RightNode as AstNodeExprImm;
            var leftType  = binary.LeftNode.Type;
            var rightType = binary.RightNode.Type;
            var Operator  = binary.Operator;

            if (leftType == rightType)
            {
                if (AstUtils.IsTypeFloat(leftType))
                {
                    var type = leftType;

                    if (leftImm != null && rightImm != null)
                    {
                        var leftValue  = Convert.ToDouble(leftImm.Value);
                        var rightValue = Convert.ToDouble(rightImm.Value);

                        switch (Operator)
                        {
                        case "+": return(new AstNodeExprImm(AstUtils.CastType(leftValue + rightValue, type)));

                        case "-": return(new AstNodeExprImm(AstUtils.CastType(leftValue - rightValue, type)));

                        case "*": return(new AstNodeExprImm(AstUtils.CastType(leftValue * rightValue, type)));

                        case "/": return(new AstNodeExprImm(AstUtils.CastType(leftValue / rightValue, type)));
                        }
                    }
                    else if (leftImm != null)
                    {
                        var leftValue = Convert.ToInt64(leftImm.Value);
                        switch (Operator)
                        {
                        case "|":
                            if (leftValue == 0)
                            {
                                return(binary.RightNode);
                            }
                            break;

                        case "+":
                            if (leftValue == 0)
                            {
                                return(binary.RightNode);
                            }
                            break;

                        case "-":
                            if (leftValue == 0)
                            {
                                return(new AstNodeExprUnop("-", binary.RightNode));
                            }
                            break;

                        case "*":
                            //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type));
                            if (leftValue == 1)
                            {
                                return(binary.RightNode);
                            }
                            break;

                        case "/":
                            //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type));
                            break;
                        }
                    }
                    else if (rightImm != null)
                    {
                        var rightValue = Convert.ToInt64(rightImm.Value);
                        switch (Operator)
                        {
                        case "|":
                            if (rightValue == 0)
                            {
                                return(binary.LeftNode);
                            }
                            break;

                        case "+":
                            if (rightValue == 0)
                            {
                                return(binary.LeftNode);
                            }
                            break;

                        case "-":
                            if (rightValue == 0)
                            {
                                return(binary.LeftNode);
                            }
                            break;

                        case "*":
                            if (rightValue == 1)
                            {
                                return(binary.LeftNode);
                            }
                            break;

                        case "/":
                            //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type));
                            break;
                        }
                    }
                }
                else
                {
                    var unop = binary.RightNode as AstNodeExprUnop;
                    if (unop != null)
                    {
                        var rightUnary = unop;
                        if (Operator == "+" || Operator == "-")
                        {
                            if (rightUnary.Operator == "-")
                            {
                                return(new AstNodeExprBinop(binary.LeftNode, Operator == "+" ? "-" : "+",
                                                            rightUnary.RightNode));
                            }
                        }
                    }

                    var type = leftType;
                    // Can optimize just literal values.
                    if (leftImm != null && rightImm != null)
                    {
                        if (AstUtils.IsTypeSigned(leftType))
                        {
                            var leftValue  = Convert.ToInt64(leftImm.Value);
                            var rightValue = Convert.ToInt64(rightImm.Value);

                            switch (Operator)
                            {
                            case "+": return(new AstNodeExprImm(AstUtils.CastType(leftValue + rightValue, type)));

                            case "-": return(new AstNodeExprImm(AstUtils.CastType(leftValue - rightValue, type)));

                            case "*": return(new AstNodeExprImm(AstUtils.CastType(leftValue * rightValue, type)));

                            case "/": return(new AstNodeExprImm(AstUtils.CastType(leftValue / rightValue, type)));

                            case "<<":
                                return(new AstNodeExprImm(AstUtils.CastType(leftValue << (int)rightValue, type)));

                            case ">>":
                                return(new AstNodeExprImm(AstUtils.CastType(leftValue >> (int)rightValue, type)));
                            }
                        }
                        else
                        {
                            var leftValue  = Convert.ToUInt64(leftImm.Value);
                            var rightValue = Convert.ToUInt64(rightImm.Value);

                            // Optimize adding 0
                            switch (Operator)
                            {
                            case "+": return(new AstNodeExprImm(AstUtils.CastType(leftValue + rightValue, type)));

                            case "-": return(new AstNodeExprImm(AstUtils.CastType(leftValue - rightValue, type)));

                            case "*": return(new AstNodeExprImm(AstUtils.CastType(leftValue * rightValue, type)));

                            case "/": return(new AstNodeExprImm(AstUtils.CastType(leftValue / rightValue, type)));

                            case "<<":
                                return(new AstNodeExprImm(AstUtils.CastType(leftValue << (int)rightValue, type)));

                            case ">>":
                                return(new AstNodeExprImm(AstUtils.CastType(leftValue >> (int)rightValue, type)));
                            }
                        }
                    }
                    else if (leftImm != null)
                    {
                        var leftValue = Convert.ToInt64(leftImm.Value);
                        switch (Operator)
                        {
                        case "&":
                            if (leftValue == 0)
                            {
                                return(new AstNodeExprImm(0));
                            }
                            break;

                        case "|":
                            if (leftValue == 0)
                            {
                                return(binary.RightNode);
                            }
                            break;

                        case "+":
                            if (leftValue == 0)
                            {
                                return(binary.RightNode);
                            }
                            break;

                        case "-":
                            if (leftValue == 0)
                            {
                                return(new AstNodeExprUnop("-", binary.RightNode));
                            }
                            break;

                        case "*":
                            //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type));
                            if (leftValue == 1)
                            {
                                return(binary.RightNode);
                            }
                            break;

                        case "/":
                            //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type));
                            break;
                        }
                    }
                    else if (rightImm != null)
                    {
                        var rightValue = Convert.ToInt64(rightImm.Value);
                        switch (Operator)
                        {
                        case "0":
                            if (rightValue == 0)
                            {
                                return(new AstNodeExprImm(0));
                            }
                            break;

                        case "|":
                            if (rightValue == 0)
                            {
                                return(binary.LeftNode);
                            }
                            break;

                        case "+":
                            if (rightValue == 0)
                            {
                                return(binary.LeftNode);
                            }
                            if (rightValue < 0)
                            {
                                return(new AstNodeExprBinop(binary.LeftNode, "-",
                                                            new AstNodeExprImm(AstUtils.Negate(rightImm.Value))));
                            }
                            break;

                        case "-":
                            if (rightValue == 0)
                            {
                                return(binary.LeftNode);
                            }
                            break;

                        case "*":
                            if (rightValue == 1)
                            {
                                return(binary.LeftNode);
                            }
                            break;

                        case "/":
                            //if (RightValue == 0) throw(new Exception("Can't divide by 0"));
                            if (rightValue == 1)
                            {
                                return(binary.LeftNode);
                            }
                            break;
                        }
                    }
                } // !AstUtils.IsTypeFloat(LeftType)
            }

            // Special optimizations
            if ((leftType == typeof(uint) || leftType == typeof(int)) && rightType == typeof(int) && rightImm != null)
            {
                var rightValue = Convert.ToInt64(rightImm.Value);
                if (Operator == ">>" && rightValue == 0)
                {
                    return(binary.LeftNode);
                }
            }

            return(binary);
        }
        protected virtual AstNode _Optimize(AstNodeExprBinop Binary)
        {
            //Console.WriteLine("Optimize.AstNodeExprBinop: {0} {1} {2}", Binary.LeftNode, Binary.Operator, Binary.RightNode);
            var LeftImm   = (Binary.LeftNode as AstNodeExprImm);
            var RightImm  = (Binary.RightNode as AstNodeExprImm);
            var LeftType  = Binary.LeftNode.Type;
            var RightType = Binary.RightNode.Type;
            var Operator  = Binary.Operator;

            if ((LeftType == RightType))
            {
                if (AstUtils.IsTypeFloat(LeftType))
                {
                    var Type = LeftType;

                    if ((LeftImm != null) && (RightImm != null))
                    {
                        var LeftValue  = Convert.ToDouble(LeftImm.Value);
                        var RightValue = Convert.ToDouble(RightImm.Value);

                        switch (Operator)
                        {
                        case "+": return(new AstNodeExprImm(AstUtils.CastType(LeftValue + RightValue, Type)));

                        case "-": return(new AstNodeExprImm(AstUtils.CastType(LeftValue - RightValue, Type)));

                        case "*": return(new AstNodeExprImm(AstUtils.CastType(LeftValue * RightValue, Type)));

                        case "/": return(new AstNodeExprImm(AstUtils.CastType(LeftValue / RightValue, Type)));
                        }
                    }
                    else if (LeftImm != null)
                    {
                        var LeftValue = Convert.ToInt64(LeftImm.Value);
                        switch (Operator)
                        {
                        case "|": if (LeftValue == 0)
                            {
                                return(Binary.RightNode);
                            }
                            break;

                        case "+": if (LeftValue == 0)
                            {
                                return(Binary.RightNode);
                            }
                            break;

                        case "-": if (LeftValue == 0)
                            {
                                return(new AstNodeExprUnop("-", Binary.RightNode));
                            }
                            break;

                        case "*":
                            //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type));
                            if (LeftValue == 1)
                            {
                                return(Binary.RightNode);
                            }
                            break;

                        case "/":
                            //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type));
                            break;
                        }
                    }
                    else if (RightImm != null)
                    {
                        var RightValue = Convert.ToInt64(RightImm.Value);
                        switch (Operator)
                        {
                        case "|": if (RightValue == 0)
                            {
                                return(Binary.LeftNode);
                            }
                            break;

                        case "+": if (RightValue == 0)
                            {
                                return(Binary.LeftNode);
                            }
                            break;

                        case "-": if (RightValue == 0)
                            {
                                return(Binary.LeftNode);
                            }
                            break;

                        case "*":
                            if (RightValue == 1)
                            {
                                return(Binary.LeftNode);
                            }
                            break;

                        case "/":
                            //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type));
                            break;
                        }
                    }
                }
                else
                {
                    if (Binary.RightNode is AstNodeExprUnop)
                    {
                        var RightUnary = Binary.RightNode as AstNodeExprUnop;
                        if (Operator == "+" || Operator == "-")
                        {
                            if (RightUnary.Operator == "-")
                            {
                                return(new AstNodeExprBinop(Binary.LeftNode, (Operator == "+") ? "-" : "+", RightUnary.RightNode));
                            }
                        }
                    }

                    var Type = LeftType;
                    // Can optimize just literal values.
                    if ((LeftImm != null) && (RightImm != null))
                    {
                        if (AstUtils.IsTypeSigned(LeftType))
                        {
                            var LeftValue  = Convert.ToInt64(LeftImm.Value);
                            var RightValue = Convert.ToInt64(RightImm.Value);

                            switch (Operator)
                            {
                            case "+": return(new AstNodeExprImm(AstUtils.CastType(LeftValue + RightValue, Type)));

                            case "-": return(new AstNodeExprImm(AstUtils.CastType(LeftValue - RightValue, Type)));

                            case "*": return(new AstNodeExprImm(AstUtils.CastType(LeftValue * RightValue, Type)));

                            case "/": return(new AstNodeExprImm(AstUtils.CastType(LeftValue / RightValue, Type)));

                            case "<<": return(new AstNodeExprImm(AstUtils.CastType(LeftValue << (int)RightValue, Type)));

                            case ">>": return(new AstNodeExprImm(AstUtils.CastType(LeftValue >> (int)RightValue, Type)));
                            }
                        }
                        else
                        {
                            var LeftValue  = Convert.ToUInt64(LeftImm.Value);
                            var RightValue = Convert.ToUInt64(RightImm.Value);

                            // Optimize adding 0
                            switch (Operator)
                            {
                            case "+": return(new AstNodeExprImm(AstUtils.CastType(LeftValue + RightValue, Type)));

                            case "-": return(new AstNodeExprImm(AstUtils.CastType(LeftValue - RightValue, Type)));

                            case "*": return(new AstNodeExprImm(AstUtils.CastType(LeftValue * RightValue, Type)));

                            case "/": return(new AstNodeExprImm(AstUtils.CastType(LeftValue / RightValue, Type)));

                            case "<<": return(new AstNodeExprImm(AstUtils.CastType(LeftValue << (int)RightValue, Type)));

                            case ">>": return(new AstNodeExprImm(AstUtils.CastType(LeftValue >> (int)RightValue, Type)));
                            }
                        }
                    }
                    else if (LeftImm != null)
                    {
                        var LeftValue = Convert.ToInt64(LeftImm.Value);
                        switch (Operator)
                        {
                        case "&": if (LeftValue == 0)
                            {
                                return(new AstNodeExprImm(0));
                            }
                            break;

                        case "|": if (LeftValue == 0)
                            {
                                return(Binary.RightNode);
                            }
                            break;

                        case "+": if (LeftValue == 0)
                            {
                                return(Binary.RightNode);
                            }
                            break;

                        case "-": if (LeftValue == 0)
                            {
                                return(new AstNodeExprUnop("-", Binary.RightNode));
                            }
                            break;

                        case "*":
                            //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type));
                            if (LeftValue == 1)
                            {
                                return(Binary.RightNode);
                            }
                            break;

                        case "/":
                            //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type));
                            break;
                        }
                    }
                    else if (RightImm != null)
                    {
                        var RightValue = Convert.ToInt64(RightImm.Value);
                        switch (Operator)
                        {
                        case "0": if (RightValue == 0)
                            {
                                return(new AstNodeExprImm(0));
                            }
                            break;

                        case "|": if (RightValue == 0)
                            {
                                return(Binary.LeftNode);
                            }
                            break;

                        case "+":
                            if (RightValue == 0)
                            {
                                return(Binary.LeftNode);
                            }
                            if (RightValue < 0)
                            {
                                return(new AstNodeExprBinop(Binary.LeftNode, "-", new AstNodeExprImm(AstUtils.Negate(RightImm.Value))));
                            }
                            break;

                        case "-": if (RightValue == 0)
                            {
                                return(Binary.LeftNode);
                            }
                            break;

                        case "*":
                            if (RightValue == 1)
                            {
                                return(Binary.LeftNode);
                            }
                            break;

                        case "/":
                            //if (RightValue == 0) throw(new Exception("Can't divide by 0"));
                            if (RightValue == 1)
                            {
                                return(Binary.LeftNode);
                            }
                            break;
                        }
                    }
                }                 // !AstUtils.IsTypeFloat(LeftType)
            }

            // Special optimizations
            if ((LeftType == typeof(uint) || LeftType == typeof(int)) && RightType == typeof(int))
            {
                if (RightImm != null)
                {
                    var RightValue = Convert.ToInt64(RightImm.Value);
                    if (Operator == ">>" && (RightValue == 0))
                    {
                        return(Binary.LeftNode);
                    }
                }
            }

            return(Binary);
        }