protected virtual AstNode _Optimize(AstNodeExprCast Cast)
        {
            //Console.WriteLine("Optimize.AstNodeExprCast: {0} : {1}", Cast.CastedType, Cast.Expr);

            // Dummy cast
            if (Cast.CastedType == Cast.Expr.Type)
            {
                //Console.WriteLine("Dummy Cast");
                return(Cast.Expr);
            }
            // Double Cast
            else if (Cast.Expr is AstNodeExprCast)
            {
                //Console.WriteLine("Double Cast");
                var FirstCastType  = (Cast.Expr as AstNodeExprCast).CastedType;
                var SecondCastType = Cast.CastedType;
                if (FirstCastType.IsPrimitive && SecondCastType.IsPrimitive)
                {
                    if (AstUtils.GetTypeSize(FirstCastType) >= AstUtils.GetTypeSize(SecondCastType))
                    {
                        return(Optimize(new AstNodeExprCast(Cast.CastedType, (Cast.Expr as AstNodeExprCast).Expr)));
                    }
                }
            }
            // Cast to immediate
            else if (Cast.Expr is AstNodeExprImm)
            {
                //Console.WriteLine("Cast to immediate");
                return(new AstNodeExprImm(AstUtils.CastType((Cast.Expr as AstNodeExprImm).Value, Cast.CastedType)));
            }

            return(Cast);
        }
Example #2
0
        protected virtual AstNode _Optimize(AstNodeExprCast cast)
        {
            //Console.WriteLine("Optimize.AstNodeExprCast: {0} : {1}", Cast.CastedType, Cast.Expr);

            // Dummy cast
            if (cast.CastedType == cast.Expr.Type)
            {
                //Console.WriteLine("Dummy Cast");
                return(cast.Expr);
            }

            // Double Cast
            var expr = cast.Expr as AstNodeExprCast;

            if (expr != null)
            {
                //Console.WriteLine("Double Cast");
                var firstCastType  = expr.CastedType;
                var secondCastType = cast.CastedType;
                if (firstCastType.IsPrimitive && secondCastType.IsPrimitive)
                {
                    if (AstUtils.GetTypeSize(firstCastType) >= AstUtils.GetTypeSize(secondCastType))
                    {
                        return(Optimize(new AstNodeExprCast(cast.CastedType, expr.Expr)));
                    }
                }

                return(cast);
            }

            // Cast to immediate
            var imm = cast.Expr as AstNodeExprImm;

            if (imm != null)
            {
                //Console.WriteLine("Cast to immediate");
                return(new AstNodeExprImm(AstUtils.CastType(imm.Value, cast.CastedType)));
            }

            return(cast);
        }
Example #3
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(AstNodeExprImm item)
        {
            var itemType  = AstUtils.GetSignedType(item.Type);
            var itemValue = item.Value;

            if (itemType.IsEnum)
            {
                itemType  = itemType.GetEnumUnderlyingType();
                itemValue = AstUtils.CastType(itemValue, itemType);
            }

            if (
                itemType == typeof(int) ||
                itemType == typeof(sbyte) ||
                itemType == typeof(short) ||
                itemType == typeof(bool)
                )
            {
                var value = (int)Convert.ToInt64(itemValue);
                switch (value)
                {
                case -1:
                    Emit(OpCodes.Ldc_I4_M1);
                    break;

                case 0:
                    Emit(OpCodes.Ldc_I4_0);
                    break;

                case 1:
                    Emit(OpCodes.Ldc_I4_1);
                    break;

                case 2:
                    Emit(OpCodes.Ldc_I4_2);
                    break;

                case 3:
                    Emit(OpCodes.Ldc_I4_3);
                    break;

                case 4:
                    Emit(OpCodes.Ldc_I4_4);
                    break;

                case 5:
                    Emit(OpCodes.Ldc_I4_5);
                    break;

                case 6:
                    Emit(OpCodes.Ldc_I4_6);
                    break;

                case 7:
                    Emit(OpCodes.Ldc_I4_7);
                    break;

                case 8:
                    Emit(OpCodes.Ldc_I4_8);
                    break;

                default:
                    Emit(OpCodes.Ldc_I4, value);
                    break;
                }
            }
            else if (itemType == typeof(long) || itemType == typeof(ulong))
            {
                Emit(OpCodes.Ldc_I8, Convert.ToInt64(itemValue));
            }
            else if (itemType == typeof(IntPtr))
            {
#if false
                Emit(OpCodes.Ldc_I8, ((IntPtr)Item.Value).ToInt64());
                Emit(OpCodes.Conv_I);
#else
                if (Environment.Is64BitProcess)
                {
                    Emit(OpCodes.Ldc_I8, ((IntPtr)item.Value).ToInt64());
                    Emit(OpCodes.Conv_I);
                }
                else
                {
                    Emit(OpCodes.Ldc_I4, ((IntPtr)item.Value).ToInt32());
                    Emit(OpCodes.Conv_I);
                }
#endif
            }
            else if (itemType == typeof(float))
            {
                Emit(OpCodes.Ldc_R4, (float)item.Value);
            }
            else if (item.Value == null)
            {
                Emit(OpCodes.Ldnull);
            }
            else if (itemType == typeof(string))
            {
                Emit(OpCodes.Ldstr, (string)item.Value);
            }
            else if (itemType == typeof(Type))
            {
                Emit(OpCodes.Ldtoken, (Type)item.Value);
                Emit(OpCodes.Call, ((Func <RuntimeTypeHandle, Type>)Type.GetTypeFromHandle).Method);
                //IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            }
            else
            {
                throw new NotImplementedException($"Can't handle immediate type {itemType}");
            }
        }
        protected virtual void _Generate(AstNodeStmSwitch Switch)
        {
            var allCaseValues = Switch.Cases.Select(Case => Case.CaseValue);
            var caseValues    = allCaseValues as IList <object> ?? allCaseValues.ToList();

            if (caseValues.Count != caseValues.Distinct().Count())
            {
                throw new Exception("Repeated case in switch!");
            }

            // Check types and unique values.

            var endCasesLabel = AstLabel.CreateLabel("EndCasesLabel");
            var defaultLabel  = AstLabel.CreateLabel("DefaultLabel");

            if (Switch.Cases.Length > 0)
            {
                var commonType = Switch.Cases.First().CaseValue.GetType();
                if (Switch.Cases.Any(Case => Case.CaseValue.GetType() != commonType))
                {
                    throw new Exception("All cases should have the same type");
                }

                var doneSpecialized = false;

                // Specialized constant-time integer switch (if possible)
                if (AstUtils.IsIntegerType(commonType))
                {
                    var commonMin   = Switch.Cases.Min(Case => AstUtils.CastType <long>(Case.CaseValue));
                    var commonMax   = Switch.Cases.Max(Case => AstUtils.CastType <long>(Case.CaseValue));
                    var casesLength = commonMax - commonMin + 1;

                    // No processing tables greater than 4096 elements.
                    if (casesLength <= 4096)
                    {
                        var labels = new AstLabel[casesLength];
                        for (var n = 0; n < casesLength; n++)
                        {
                            labels[n] = defaultLabel;
                        }

                        foreach (var Case in Switch.Cases)
                        {
                            var realValue = AstUtils.CastType <long>(Case.CaseValue);
                            var offset    = realValue - commonMin;
                            labels[offset] = AstLabel.CreateLabel("Case_" + realValue);
                        }

                        /*
                         * //var SwitchVarLocal = AstLocal.Create(AllCaseValues.First().GetType(), "SwitchVarLocal" + SwitchVarCount++);
                         * //Generate(new AstNodeStmAssign(new AstNodeExprLocal(SwitchVarLocal), Switch.SwitchValue - new AstNodeExprCast(CommonType, CommonMin)));
                         * //Generate(new AstNodeStmIfElse(new AstNodeExprBinop(new AstNodeExprLocal(SwitchVarLocal), "<", 0), new AstNodeStmGotoAlways(DefaultLabel)));
                         * //Generate(new AstNodeStmIfElse(new AstNodeExprBinop(new AstNodeExprLocal(SwitchVarLocal), ">=", CasesLength), new AstNodeStmGotoAlways(DefaultLabel)));
                         * //Generate(new AstNodeExprLocal(SwitchVarLocal));
                         */

                        Generate(Switch.SwitchValue - new AstNodeExprCast(commonType, commonMin));
                        Emit(OpCodes.Switch, labels);
                        Generate(new AstNodeStmGotoAlways(defaultLabel));
                        foreach (var Case in Switch.Cases)
                        {
                            var realValue = AstUtils.CastType <long>(Case.CaseValue);
                            var offset    = realValue - commonMin;
                            Generate(new AstNodeStmLabel(labels[offset]));
                            {
                                Generate(Case.Code);
                            }
                            Generate(new AstNodeStmGotoAlways(endCasesLabel));
                        }

                        doneSpecialized = true;
                    }
                    else
                    {
                        // TODO: find a common shift and masks for all the values to reduce CasesLength.
                        // TODO: On too large test cases, split them recursively in:
                        // if (Var < Half) { switch(Var - LowerPartMin) { ... } } else { switch(Var - Half - UpperPartMin) { ... } }
                    }
                }
                // Specialized switch for strings (checking length, then hash, then contents)
                else if (commonType == typeof(string))
                {
                    // TODO!
                }

                // Generic if/else
                if (!doneSpecialized)
                {
                    var switchVarLocal =
                        AstLocal.Create(caseValues.First().GetType(), "SwitchVarLocal" + _switchVarCount++);
                    Generate(new AstNodeStmAssign(new AstNodeExprLocal(switchVarLocal), Switch.SwitchValue));
                    //Switch.Cases
                    foreach (var Case in Switch.Cases)
                    {
                        var labelSkipThisCase = AstLabel.CreateLabel("LabelCase" + Case.CaseValue);
                        Generate(new AstNodeStmGotoIfFalse(labelSkipThisCase,
                                                           new AstNodeExprBinop(new AstNodeExprLocal(switchVarLocal), "==",
                                                                                new AstNodeExprImm(Case.CaseValue))));
                        Generate(Case.Code);
                        Generate(new AstNodeStmGotoAlways(endCasesLabel));
                        Generate(new AstNodeStmLabel(labelSkipThisCase));
                    }
                }
            }

            Generate(new AstNodeStmLabel(defaultLabel));
            if (Switch.CaseDefault != null)
            {
                Generate(Switch.CaseDefault.Code);
            }

            Generate(new AstNodeStmLabel(endCasesLabel));
        }
        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);
        }