Exemplo n.º 1
0
 protected virtual void _Generate(AstNodeExprBinop item)
 {
     Output.Write("(");
     Generate(item.LeftNode);
     Output.Write(" " + item.Operator + " ");
     Generate(item.RightNode);
     Output.Write(")");
 }
Exemplo n.º 2
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 void _Generate(AstNodeExprBinop item)
        {
            var leftType = item.LeftNode.Type;

            //var rightType = item.RightNode.Type;

            //if (LeftType != RightType) throw(new Exception(String.Format("BinaryOp Type mismatch ({0}) != ({1})", LeftType, RightType)));

            //Item.GetType().GenericTypeArguments[0]
            Generate(item.LeftNode);
            Generate(item.RightNode);

            //switch (Item.Operator)
            //{
            //	case "||":
            //	case "&&":
            //		if (LeftType != typeof(bool) || RightType != typeof(bool))
            //		{
            //			throw(new InvalidOperationException(String.Format("Operator '{0}' requires boolean types but found {1}, {2}", Item.Operator, LeftType, RightType)));
            //		}
            //		break;
            //}

            switch (item.Operator)
            {
            case "+":
                Emit(OpCodes.Add);
                break;

            case "-":
                Emit(OpCodes.Sub);
                break;

            case "*":
                Emit(OpCodes.Mul);
                break;

            case "/":
                Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Div : OpCodes.Div_Un);
                break;

            case "%":
                Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Rem : OpCodes.Rem_Un);
                break;

            case "==":
                Emit(OpCodes.Ceq);
                break;

            case "!=":
                Emit(OpCodes.Ceq);
                Emit(OpCodes.Ldc_I4_0);
                Emit(OpCodes.Ceq);
                break;

            case "<":
                Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Clt : OpCodes.Clt_Un);
                break;

            case ">":
                Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Cgt : OpCodes.Cgt_Un);
                break;

            case "<=":
                Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Cgt : OpCodes.Cgt_Un);
                Emit(OpCodes.Ldc_I4_0);
                Emit(OpCodes.Ceq);
                break;

            case ">=":
                Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Clt : OpCodes.Clt_Un);
                Emit(OpCodes.Ldc_I4_0);
                Emit(OpCodes.Ceq);
                break;

            case "&":
            case "&&":
                Emit(OpCodes.And);
                break;

            case "|":
            case "||":
                Emit(OpCodes.Or);
                break;

            case "^":
                Emit(OpCodes.Xor);
                break;

            case "<<":
                Emit(OpCodes.Shl);
                break;

            case ">>":
                Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Shr : OpCodes.Shr_Un);
                break;

            default: throw new NotImplementedException($"Not implemented operator '{item.Operator}'");
            }
        }
        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);
        }