Example #1
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            // Convert IntPtr.Zero
            foreach (var node in ast.GetExpressions(AstCode.Ldsfld))
            {
                var field = (XFieldReference)node.Operand;
                if (field.DeclaringType.IsIntPtr() && (field.Name == "Zero"))
                {
                    node.Code    = AstCode.Ldnull;
                    node.Operand = null;
                    node.Arguments.Clear();
                    node.SetType(compiler.Module.TypeSystem.Object);
                }
            }

            // Convert box(IntPtr)
            foreach (var node in ast.GetExpressions(AstCode.Box))
            {
                var type = (XTypeReference)node.Operand;
                if (type.IsIntPtr())
                {
                    node.CopyFrom(node.Arguments[0]);
                }
            }
        }
Example #2
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            // Convert IntPtr.Zero
            foreach (var node in ast.GetExpressions(AstCode.Ldsfld))
            {
                var field = (XFieldReference)node.Operand;
                if (field.DeclaringType.IsIntPtr() && (field.Name == "Zero"))
                {
                    node.Code = AstCode.Ldnull;
                    node.Operand = null;
                    node.Arguments.Clear();
                    node.SetType(compiler.Module.TypeSystem.Object);
                }                
            }

            // Convert box(IntPtr)
            foreach (var node in ast.GetExpressions(AstCode.Box))
            {
                var type = (XTypeReference)node.Operand;
                if (type.IsIntPtr())
                {
                    node.CopyFrom(node.Arguments[0]);
                }
            }
        }
Example #3
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast, AssemblyCompiler compiler)
 {
     // Optimize enum2int(ldsfld(enum-const))
     foreach (var node in ast.GetExpressions())
     {
         switch (node.Code)
         {
         case AstCode.Enum_to_int:
         case AstCode.Enum_to_long:
         {
             var             arg = node.Arguments[0];
             XFieldReference fieldRef;
             if (arg.Match(AstCode.Ldsfld, out fieldRef))
             {
                 XFieldDefinition field;
                 object           value;
                 if (fieldRef.TryResolve(out field) && field.IsStatic && field.DeclaringType.IsEnum && field.TryGetEnumValue(out value))
                 {
                     // Replace with ldc_ix
                     var wide = (node.Code == AstCode.Enum_to_long);
                     node.SetCode(wide ? AstCode.Ldc_I8 : AstCode.Ldc_I4);
                     node.Operand = wide ? (object)XConvert.ToLong(value) : XConvert.ToInt(value);
                     node.Arguments.Clear();
                 }
             }
         }
         break;
         }
     }
 }
Example #4
0
        private static void ConvertBeqBneWithConstToBrtrueBrfalse(AstNode ast)
        {
            // Convert beq/bne (cxx(x,x), 0/null/false/true) expressions to brtrue/brfalse
            foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.__Beq || x.Code == AstCode.__Bne_Un)).Reverse())
            {
                bool?reverse = ReverseCodeOnEqualCollapse(node);

                if (reverse == null)
                {
                    continue;
                }

                var expr = node.Arguments[0];

                if (node.Code == AstCode.__Bne_Un)
                {
                    reverse = !reverse;
                }

                var code = reverse.Value ? AstCode.Brfalse : AstCode.Brtrue;

                var newExpr = new AstExpression(expr.SourceLocation, code, node.Operand, expr);
                node.CopyFrom(newExpr, true);
            }
        }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast)
        {
            foreach (var node in ast.GetExpressions())
            {
                switch (node.Code)
                {
                case AstCode.Stloc:
                {
                    var variable = (AstVariable)node.Operand;
                    var varType  = variable.Type;
                    var arg      = node.Arguments[0];
                    ConvertIfNeeded(arg, varType);
                }
                break;

                case AstCode.Stelem_I2:
                {
                    var arrayElementType = node.Arguments[0].GetResultType().ElementType;
                    var arg = node.Arguments[2];
                    ConvertIfNeeded(arg, arrayElementType);
                }
                break;
                }
            }
        }
Example #6
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast, AssemblyCompiler compiler)
 {
     // Optimize enum2int(ldsfld(enum-const))
     foreach (var node in ast.GetExpressions())
     {
         switch (node.Code)
         {
             case AstCode.Enum_to_int:
             case AstCode.Enum_to_long:
                 {
                     var arg = node.Arguments[0];
                     XFieldReference fieldRef;
                     if (arg.Match(AstCode.Ldsfld, out fieldRef))
                     {
                         XFieldDefinition field;
                         object value;
                         if (fieldRef.TryResolve(out field) && field.IsStatic && field.DeclaringType.IsEnum && field.TryGetEnumValue(out value))
                         {
                             // Replace with ldc_ix
                             var wide = (node.Code == AstCode.Enum_to_long);
                             node.SetCode(wide ? AstCode.Ldc_I8 : AstCode.Ldc_I4);
                             node.Operand = wide ? (object)XConvert.ToLong(value) : XConvert.ToInt(value);
                             node.Arguments.Clear();
                         }
                     }
                 }
                 break;
         }
     }
 }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast)
        {
            foreach (var node in ast.GetExpressions(AstCode.Stloc))
            {
                // Select the nodes to work on
                var ldCode = AstCode.Ldloc;

                var stArg = node.Arguments[0];
                AstCode newCode;
                if ((stArg.Arguments.Count >= 1) && (operatorMap.TryGetValue(stArg.Code, out newCode)))
                {
                    // Found matching operator
                    var ldArg = stArg.Arguments[0];
                    if (ldArg.Code == ldCode)
                    {
                        // Found a matching 'load' opcode.
                        if (ldArg.Operand == node.Operand)
                        {
                            var type = stArg.GetResultType();
                            if (!type.IsEnum())
                            {
                                // Found matching "local" 
                                node.Code = newCode;
                                node.SetArguments(stArg.Arguments.Skip(1));
                                node.SetType(type);
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast)
        {
            foreach (var node in ast.GetExpressions(AstCode.Stloc))
            {
                // Select the nodes to work on
                var ldCode = AstCode.Ldloc;

                var     stArg = node.Arguments[0];
                AstCode newCode;
                if ((stArg.Arguments.Count >= 1) && (operatorMap.TryGetValue(stArg.Code, out newCode)))
                {
                    // Found matching operator
                    var ldArg = stArg.Arguments[0];
                    if (ldArg.Code == ldCode)
                    {
                        // Found a matching 'load' opcode.
                        if (ldArg.Operand == node.Operand)
                        {
                            var type = stArg.GetResultType();
                            if (!type.IsEnum())
                            {
                                // Found matching "local"
                                node.Code = newCode;
                                node.SetArguments(stArg.Arguments.Skip(1));
                                node.SetType(type);
                            }
                        }
                    }
                }
            }
        }
Example #9
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast)
        {
            foreach (var node in ast.GetExpressions())
            {
                switch (node.Code)
                {
                case AstCode.ByRefOutArray:
                    node.Arguments.Clear();
                    return;

                case AstCode.Conv_U2:
                    if (node.GetResultType().IsChar() && node.Arguments[0].Match(AstCode.Int_to_ushort))
                    {
                        // Remove useless conversion (int_to_ushort followed by conv_u2)
                        var value = node.Arguments[0].Arguments[0];

                        if (value.GetResultType().IsChar())
                        {
                            node.CopyFrom(value);
                        }
                        else
                        {
                            // keep the conv_u2 but drop the int_to_ushort.
                            // TODO:maybe there is a better way to do the conversion in one step.
                            // Convert.ToUInt16(char) looks now like this:

                            // .method public static ToUInt16(C)S
                            //    .registers 3
                            //    .param p0    # C

                            //    #v0=(Uninit);p0=(Char);
                            //    int-to-char v0, p0
                            //    #v0=(Char);

                            //    #v1=(Uninit);
                            //    const v1, 0xffff
                            //    #v1=(Char);

                            //    #v0=(Char);v1=(Char);
                            //    and-int/2addr v0, v1
                            //    #v0=(Integer);

                            //    #v0=(Integer);
                            //    return v0
                            //.end method

                            node.Arguments.Clear();
                            node.Arguments.Add(value);
                        }
                    }
                    break;
                }
            }
        }
Example #10
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast)
        {
            foreach (var node in ast.GetExpressions())
            {
                switch (node.Code)
                {
                    case AstCode.ByRefOutArray:
                        node.Arguments.Clear();
                        return;
                    case AstCode.Conv_U2:
                        if (node.GetResultType().IsChar() && node.Arguments[0].Match(AstCode.Int_to_ushort))
                        {
                            // Remove useless conversion (int_to_ushort followed by conv_u2)
                            var value = node.Arguments[0].Arguments[0];

                            if (value.GetResultType().IsChar())
                            {
                                node.CopyFrom(value);
                            }
                            else
                            {
                                // keep the conv_u2 but drop the int_to_ushort.
                                // TODO:maybe there is a better way to do the conversion in one step.
                                // Convert.ToUInt16(char) looks now like this:

                                // .method public static ToUInt16(C)S
                                //    .registers 3
                                //    .param p0    # C

                                //    #v0=(Uninit);p0=(Char);
                                //    int-to-char v0, p0
                                //    #v0=(Char);

                                //    #v1=(Uninit);
                                //    const v1, 0xffff
                                //    #v1=(Char);

                                //    #v0=(Char);v1=(Char);
                                //    and-int/2addr v0, v1
                                //    #v0=(Integer);

                                //    #v0=(Integer);
                                //    return v0
                                //.end method

                                node.Arguments.Clear();
                                node.Arguments.Add(value);
                            }
                        }
                        break;
                }
            }
        }
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     foreach (var node in ast.GetExpressions())
     {
         if (node.Code == AstCode.Ldloc)
         {
             var variable = (AstVariable)node.Operand;
             var varType  = variable.Type;
             var expType  = node.ExpectedType;
             if ((expType != null) && (!varType.IsSame(expType)))
             {
                 if (varType.IsByte() && (expType.IsChar() || expType.IsUInt16()))
                 {
                     var ldloc = new AstExpression(node);
                     var code  = expType.IsUInt16() ? AstCode.Int_to_ushort : AstCode.Conv_U2;
                     node.CopyFrom(new AstExpression(node.SourceLocation, code, null, ldloc).SetType(expType));
                 }
             }
         }
         else if (node.Code.IsCall())
         {
             var methodRef  = (XMethodReference)node.Operand;
             var returnType = methodRef.ReturnType;
             var expType    = node.ExpectedType;
             if ((expType != null) && (!returnType.IsSame(expType)))
             {
                 if (returnType.IsByte() && (expType.IsChar() || expType.IsUInt16()))
                 {
                     var ldloc = new AstExpression(node);
                     var code  = expType.IsUInt16() ? AstCode.Int_to_ushort : AstCode.Conv_U2;
                     node.CopyFrom(new AstExpression(node.SourceLocation, code, null, ldloc).SetType(expType));
                 }
                 else if (returnType.IsUInt16() && expType.IsChar())
                 {
                     var ldloc = new AstExpression(node);
                     node.CopyFrom(new AstExpression(node.SourceLocation, AstCode.Conv_U2, null, ldloc).SetType(expType));
                 }
                 else if (returnType.IsChar() && expType.IsUInt16())
                 {
                     var ldloc = new AstExpression(node);
                     node.CopyFrom(new AstExpression(node.SourceLocation, AstCode.Int_to_ushort, null, ldloc).SetType(expType));
                 }
             }
         }
     }
 }
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     foreach (var node in ast.GetExpressions())
     {
         if (node.Code == AstCode.Ldloc)
         {
             var variable = (AstVariable) node.Operand;
             var varType = variable.Type;
             var expType = node.ExpectedType;
             if ((expType != null) && (!varType.IsSame(expType)))
             {
                 if (varType.IsByte() && (expType.IsChar() || expType.IsUInt16()))
                 {
                     var ldloc = new AstExpression(node);
                     var code = expType.IsUInt16() ? AstCode.Int_to_ushort : AstCode.Conv_U2;
                     node.CopyFrom(new AstExpression(node.SourceLocation, code, null, ldloc).SetType(expType));
                 } 
             }
         }
         else if (node.Code.IsCall())
         {
             var methodRef = (XMethodReference) node.Operand;
             var returnType = methodRef.ReturnType;
             var expType = node.ExpectedType;
             if ((expType != null) && (!returnType.IsSame(expType)))
             {
                 if (returnType.IsByte() && (expType.IsChar() || expType.IsUInt16()))
                 {
                     var ldloc = new AstExpression(node);
                     var code = expType.IsUInt16() ? AstCode.Int_to_ushort : AstCode.Conv_U2;
                     node.CopyFrom(new AstExpression(node.SourceLocation, code, null, ldloc).SetType(expType));
                 }
                 else if (returnType.IsUInt16() && expType.IsChar())
                 {
                     var ldloc = new AstExpression(node);
                     node.CopyFrom(new AstExpression(node.SourceLocation, AstCode.Conv_U2, null, ldloc).SetType(expType));
                 }
                 else if (returnType.IsChar() && expType.IsUInt16())
                 {
                     var ldloc = new AstExpression(node);
                     node.CopyFrom(new AstExpression(node.SourceLocation, AstCode.Int_to_ushort, null, ldloc).SetType(expType));
                 }
             }
         }
     }
 }
Example #13
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast, AssemblyCompiler compiler)
 {
     foreach (var node in ast.GetExpressions())
     {
         AstExpression arg1;
         XMethodReference method;
         if (node.Match(AstCode.Call, out method, out arg1) && arg1.Match(AstCode.Ldtoken))
         {
             if ((method.Name == "GetTypeFromHandle") && method.DeclaringType.IsSystemType())
             {
                 node.Code = AstCode.TypeOf;
                 node.Operand = arg1.Operand;
                 node.Arguments.Clear();
                 node.SetType(compiler.Module.TypeSystem.Type);
             }
         }
     }
 }
Example #14
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast, AssemblyCompiler compiler)
 {
     foreach (var node in ast.GetExpressions())
     {
         AstExpression    arg1;
         XMethodReference method;
         if (node.Match(AstCode.Call, out method, out arg1) && arg1.Match(AstCode.Ldtoken))
         {
             if ((method.Name == "GetTypeFromHandle") && method.DeclaringType.IsSystemType())
             {
                 node.Code    = AstCode.TypeOf;
                 node.Operand = arg1.Operand;
                 node.Arguments.Clear();
                 node.SetType(compiler.Module.TypeSystem.Type);
             }
         }
     }
 }
Example #15
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     foreach (var node in ast.GetExpressions())
     {
         switch (node.Code)
         {
             case AstCode.ByRefOutArray:
                 node.Arguments.Clear();
                 return;
             case AstCode.Conv_U2:
                 if (node.GetResultType().IsChar() && node.Arguments[0].Match(AstCode.Int_to_ushort))
                 {
                     // Remove useless conversion (int_to_ushort followed by conv_u2)
                     var value = node.Arguments[0].Arguments[0];
                     node.CopyFrom(value);
                 }
                 break;
         }
     }
 }
Example #16
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     foreach (var node in ast.GetExpressions())
     {
         if ((node.Code == AstCode.Conv_U8) && (node.Arguments[0].Code == AstCode.Ldc_I4))
         {
             var value = node.Arguments[0].Operand;
             node.Code = AstCode.Ldc_I8;
             node.Arguments.Clear();
             node.Operand = XConvert.ToLong(value) & 0xFFFFFFFFL;
         }
         else if ((node.Code == AstCode.Ldc_I4) || (node.Code == AstCode.Ldc_R4))
         {
             var type = node.GetResultType();
             if (type.IsWide())
             {
                 node.Code = (node.Code == AstCode.Ldc_I4) ? AstCode.Ldc_I8 : AstCode.Ldc_R8;
             }
         }
     }
 }
Example #17
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast)
        {
            foreach (var node in ast.GetExpressions())
            {
                switch (node.Code)
                {
                case AstCode.ByRefOutArray:
                    node.Arguments.Clear();
                    return;

                case AstCode.Conv_U2:
                    if (node.GetResultType().IsChar() && node.Arguments[0].Match(AstCode.Int_to_ushort))
                    {
                        // Remove useless conversion (int_to_ushort followed by conv_u2)
                        var value = node.Arguments[0].Arguments[0];
                        node.CopyFrom(value);
                    }
                    break;
                }
            }
        }
Example #18
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast)
        {
            // Optimize brtrue (cxx(int, int)) expressions
            foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Brtrue) || (x.Code == AstCode.Brfalse)))
            {
                var expr = node.Arguments[0];
                if (expr.Code.IsCompare() && (expr.Arguments.Count == 2))
                {
                    var arg1 = expr.Arguments[0];
                    var arg2 = expr.Arguments[1];

                    if (arg1.IsInt32() && arg2.IsInt32())
                    {
                        // Simplify
                        var code    = (node.Code == AstCode.Brtrue) ? expr.Code : expr.Code.Reverse();
                        var newExpr = new AstExpression(node.SourceLocation, code.ToBranch(), node.Operand, arg1, arg2);
                        node.CopyFrom(newExpr);
                    }
                }
            }
        }
Example #19
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     foreach (var node in ast.GetExpressions())
     {
         if ((node.Code == AstCode.Conv_U8) && (node.Arguments[0].Code == AstCode.Ldc_I4))
         {
             var value = node.Arguments[0].Operand;
             node.Code = AstCode.Ldc_I8;
             node.Arguments.Clear();
             node.Operand = XConvert.ToLong(value) & 0xFFFFFFFFL;
         }
         else if ((node.Code == AstCode.Ldc_I4) || (node.Code == AstCode.Ldc_R4))
         {
             var type = node.GetResultType();
             if (type.IsWide())
             {
                 node.Code = (node.Code == AstCode.Ldc_I4) ? AstCode.Ldc_I8 : AstCode.Ldc_R8;
             }
         }
     }
 }
Example #20
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast)
        {
            // Optimize brtrue (cxx(int, int)) expressions
            foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Brtrue) || (x.Code == AstCode.Brfalse)))
            {
                var expr = node.Arguments[0];
                if (expr.Code.IsCompare() && (expr.Arguments.Count == 2))
                {
                    var arg1 = expr.Arguments[0];
                    var arg2 = expr.Arguments[1];

                    if (arg1.IsInt32() && arg2.IsInt32())
                    {
                        // Simplify
                        var code = (node.Code == AstCode.Brtrue) ? expr.Code : expr.Code.Reverse();
                        var newExpr = new AstExpression(expr.SourceLocation, code.ToBranch(), node.Operand, arg1, arg2);
                        node.CopyFrom(newExpr, true);
                    }
                }
            }
        }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast)
        {
            foreach (var node in ast.GetExpressions())
            {
                switch (node.Code)
                {
                case AstCode.Stloc:
                {
                    var variable = (AstVariable)node.Operand;
                    var varType  = variable.Type;
                    var arg      = node.Arguments[0];
                    ConvertIfNeeded(arg, varType);
                }
                break;

                case AstCode.Ret:
                {
                    // TODO: whats the difference between this and RLBuilder.ConvertTypeBeforeStore?
                    if (node.Arguments.Count > 0)
                    {
                        var varType = node.Arguments[0].ExpectedType;
                        if (varType != null)
                        {
                            var arg = node.Arguments[0];
                            ConvertForRetIfNeeded(arg, varType);
                        }
                    }
                }
                break;

                case AstCode.Stelem_I2:
                {
                    var arrayElementType = node.Arguments[0].GetResultType().ElementType;
                    var arg = node.Arguments[2];
                    ConvertIfNeeded(arg, arrayElementType);
                }
                break;
                }
            }
        }
Example #22
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
 {
     foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Call) || (x.Code == AstCode.Calli) || (x.Code == AstCode.Callvirt)))
     {
         var method = (XMethodReference)node.Operand;
         XMethodDefinition methodDef;
         if (method.TryResolve(out methodDef) && methodDef.IsConstructor && methodDef.DeclaringType.IsPrimitive && (node.Arguments.Count == 2))
         {
             // primitive.ctor(addressof_primitive, value) -> primitive.cast(value)
             var locVar = node.Arguments[0].Operand;
             node.Arguments.RemoveAt(0);
             node.SetCode(AstCode.Stloc).SetType(node.Arguments[0].GetResultType()).Operand = locVar;
         }
         else
         {
             for (var i = 0; i < node.Arguments.Count; i++)
             {
                 ProcessArgument(node, method, i, currentMethod, compiler.Module);
             }
         }
     }
 }
Example #23
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     foreach (var node in ast.GetExpressions(AstCode.Newobj))
     {
         var method = (XMethodReference)node.Operand;
         if (method.Name == ".ctor")
         {
             XTypeDefinition declaringType;
             if (method.DeclaringType.TryResolve(out declaringType) && declaringType.IsDelegate())
             {
                 var ldftn = node.Arguments[1];
                 if ((ldftn.Code == AstCode.Ldftn) || (ldftn.Code == AstCode.Ldvirtftn))
                 {
                     var token = (XMethodReference)ldftn.Operand;
                     node.Code    = AstCode.Delegate;
                     node.Operand = Tuple.Create(declaringType, token.GetElementMethod().Resolve());
                     node.Arguments.RemoveAt(1);
                 }
             }
         }
     }
 }
Example #24
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     foreach (var node in ast.GetExpressions(AstCode.Newobj))
     {
         var method = (XMethodReference) node.Operand;
         if (method.Name == ".ctor")
         {
             XTypeDefinition declaringType;
             if (method.DeclaringType.TryResolve(out declaringType) && declaringType.IsDelegate())
             {
                 var ldftn = node.Arguments[1];
                 if ((ldftn.Code == AstCode.Ldftn) || (ldftn.Code == AstCode.Ldvirtftn))
                 {
                     var token = (XMethodReference) ldftn.Operand;
                     node.Code = AstCode.Delegate;
                     node.Operand = Tuple.Create(declaringType, token.GetElementMethod().Resolve());
                     node.Arguments.RemoveAt(1);
                 }
             }
         }
     }
 }
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
 {
     foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Call) || (x.Code == AstCode.Calli) || (x.Code == AstCode.Callvirt)))
     {
         var method = (XMethodReference)node.Operand;
         XMethodDefinition methodDef;
         if (method.TryResolve(out methodDef) && methodDef.IsConstructor && methodDef.DeclaringType.IsPrimitive && (node.Arguments.Count == 2))
         {
             // primitive.ctor(addressof_primitive, value) -> primitive.cast(value)
             var locVar = node.Arguments[0].Operand;
             node.Arguments.RemoveAt(0);
             node.SetCode(AstCode.Stloc).SetType(node.Arguments[0].GetResultType()).Operand = locVar;
         }
         else
         {
             for (var i = 0; i < node.Arguments.Count; i++)
             {
                 ProcessArgument(node, method, i, currentMethod, compiler.Module);
             }
         }
     }
 }
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     foreach (var node in ast.GetExpressions())
     {
         switch (node.Code)
         {
             case AstCode.Stloc:
                 {
                     var variable = (AstVariable)node.Operand;
                     var varType = variable.Type;
                     var arg = node.Arguments[0];
                     ConvertIfNeeded(arg, varType);                            
                 }
                 break;
             case AstCode.Ret:
                 {
                     // TODO: whats the difference between this and RLBuilder.ConvertTypeBeforeStore?
                     if (node.Arguments.Count > 0)
                     {
                         var varType = node.Arguments[0].ExpectedType;
                         if (varType != null)
                         {
                             var arg = node.Arguments[0];
                             ConvertForRetIfNeeded(arg, varType);
                         }
                     }
                 }
                 break;
             case AstCode.Stelem_I2:
                 {
                     var arrayElementType = node.Arguments[0].GetResultType().ElementType;
                     var arg = node.Arguments[2];
                     ConvertIfNeeded(arg, arrayElementType);
                 }
                 break;
         }
     }
 }
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     foreach (var node in ast.GetExpressions(AstCode.Cgt_Un))
     {
         if ((node.Arguments.Count == 2) && (node.Arguments[1].Code == AstCode.Ldnull))
         {
             if (node.Arguments[0].Code == AstCode.Isinst)
             {
                 // Cgt_un(IsInst(x), ldnull) -> InstanceOf(x)
                 var argX = node.Arguments[0].Arguments[0];
                 node.Operand = node.Arguments[0].Operand;
                 node.Code = AstCode.InstanceOf;
                 node.Arguments.Clear();
                 node.Arguments.Add(argX);
             }
             else
             {
                 // Cgt_un(x, ldnull) -> CIsNotNull(x)
                 node.Arguments.RemoveAt(1);
                 node.Code = AstCode.CIsNotNull;
             }
         }
     }
 }
Example #28
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     foreach (var node in ast.GetExpressions(AstCode.Cgt_Un))
     {
         if ((node.Arguments.Count == 2) && (node.Arguments[1].Code == AstCode.Ldnull))
         {
             if (node.Arguments[0].Code == AstCode.Isinst)
             {
                 // Cgt_un(IsInst(x), ldnull) -> InstanceOf(x)
                 var argX = node.Arguments[0].Arguments[0];
                 node.Operand = node.Arguments[0].Operand;
                 node.Code    = AstCode.InstanceOf;
                 node.Arguments.Clear();
                 node.Arguments.Add(argX);
             }
             else
             {
                 // Cgt_un(x, ldnull) -> CIsNotNull(x)
                 node.Arguments.RemoveAt(1);
                 node.Code = AstCode.CIsNotNull;
             }
         }
     }
 }
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     foreach (var node in ast.GetExpressions())
     {
         switch (node.Code)
         {
             case AstCode.Stloc:
                 {
                     var variable = (AstVariable)node.Operand;
                     var varType = variable.Type;
                     var arg = node.Arguments[0];
                     ConvertIfNeeded(arg, varType);                            
                 }
                 break;
             case AstCode.Stelem_I2:
                 {
                     var arrayElementType = node.Arguments[0].GetResultType().ElementType;
                     var arg = node.Arguments[2];
                     ConvertIfNeeded(arg, arrayElementType);
                 }
                 break;
         }
     }
 }
Example #30
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            foreach (var node in ast.GetExpressions(AstCode.Call))
            {
                var method = node.Operand as XMethodReference;
                if ((method != null) && method.DeclaringType.GetElementType().IsNullableT())
                {
                    var git  = (XGenericInstanceType)method.DeclaringType;
                    var type = git.GenericArguments[0];
                    if ((node.Arguments.Count == 2) && (method.Name == ".ctor"))
                    {
                        var target = node.Arguments[0];
                        var value  = node.Arguments[1];

                        if (type.IsPrimitive)
                        {
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                                ConvertPrimitiveCtor(node, method, type, target, value);
                                break;
                            }
                        }
                        else
                        {
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                                ConvertOtherCtor(node, type, target, value);
                                break;
                            }
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "get_HasValue"))
                    {
                        var target = node.Arguments[0];
                        switch (target.Code)
                        {
                        case AstCode.Ldloca:
                        case AstCode.Ldflda:
                        case AstCode.Ldsflda:
                        case AstCode.Ldloc:
                        case AstCode.Ldfld:
                        case AstCode.Ldsfld:
                            ConvertHasValue(node, type, target);
                            break;
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "get_Value"))
                    {
                        if (type.IsPrimitive)
                        {
                            var target = node.Arguments[0];
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                            case AstCode.Ldloc:
                            case AstCode.Ldfld:
                            case AstCode.Ldsfld:
                                ConvertPrimitiveGetValue(node, method, type, target, compiler.Module);
                                break;
                            }
                        }
                        else
                        {
                            var target = node.Arguments[0];
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                            case AstCode.Ldloc:
                            case AstCode.Ldfld:
                            case AstCode.Ldsfld:
                                ConvertOtherGetValue(node, method, type, target, compiler.Module);
                                break;
                            }
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "GetValueOrDefault"))
                    {
                        if (type.IsPrimitive)
                        {
                            var target = node.Arguments[0];
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                            case AstCode.Ldloc:
                            case AstCode.Ldfld:
                            case AstCode.Ldsfld:
                                ConvertPrimitiveGetValueOrDefault(node, method, type, target, compiler.Module);
                                break;
                            }
                        }
                        else
                        {
                            var target = node.Arguments[0];
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                            case AstCode.Ldloc:
                            case AstCode.Ldfld:
                            case AstCode.Ldsfld:
                                ConvertOtherGetValueOrDefault(node, type);
                                break;
                            }
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "get_RawValue"))
                    {
                        var target = node.Arguments[0];
                        if (type.IsPrimitive)
                        {
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                                ConvertPrimitiveGetRawValue(node, type, target);
                                break;
                            }
                        }
                        else
                        {
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                                ConvertOtherGetRawValue(node, type, target);
                                break;
                            }
                        }
                    }
                    else if (type.IsPrimitive || type.IsEnum())
                    {
                        // Convert ld_a to ld
                        foreach (var target in node.Arguments)
                        {
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                                ConvertLoad(target);
                                break;
                            }
                        }
                    }
                }
            }

            foreach (var node in ast.GetExpressions(AstCode.Newobj))
            {
                var method = node.Operand as XMethodReference;
                if ((method != null) && method.DeclaringType.GetElementType().IsNullableT())
                {
                    var git  = (XGenericInstanceType)method.DeclaringType;
                    var type = git.GenericArguments[0];
                    if ((node.Arguments.Count == 1) && (method.Name == ".ctor"))
                    {
                        var value = node.Arguments[0];

                        if (type.IsPrimitive)
                        {
                            ConvertPrimitiveNewObj(node, method, type, value);
                        }
                        else
                        {
                            ConvertOtherNewObj(node, method, type, value);
                        }
                    }
                }
            }
        }
Example #31
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            var typeSystem = compiler.Module.TypeSystem;

            foreach (var node in ast.GetExpressions().Reverse())
            {
                if ((node.Code == AstCode.Ldc_I4) || (node.Code == AstCode.Ldc_I8))
                {
                    var             typeRef = node.InferredType;
                    XTypeDefinition typeDef;
                    if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                    {
                        // Convert to ld-enum-value
                        XFieldDefinition field;
                        if (typeDef.TryGetEnumConstField(node.Operand, out field))
                        {
                            // Convert to ldsfld
                            node.Code         = AstCode.Ldsfld;
                            node.Operand      = field;
                            node.InferredType = typeDef;
                            node.ExpectedType = typeDef;
                        }
                        else
                        {
                            // Call Enum.GetValue(enumType, value)
                            var module    = compiler.Module;
                            var valueType = (node.Code == AstCode.Ldc_I8)
                                                ? module.TypeSystem.Long
                                                : module.TypeSystem.Int;
                            var value = new AstExpression(node)
                            {
                                InferredType = valueType, ExpectedType = valueType
                            };
                            node.Code         = (node.Code == AstCode.Ldc_I8) ? AstCode.Long_to_enum : AstCode.Int_to_enum;
                            node.Operand      = null;
                            node.InferredType = typeDef;
                            node.ExpectedType = typeDef;
                            node.Arguments.Clear();
                            node.Arguments.Add(value);
                        }
                    }
                }
                else if (node.Code.IsBinaryOperation())
                {
                    var             typeRef = node.InferredType;
                    XTypeDefinition typeDef;
                    if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                    {
                        ConvertBinOp(node, typeDef, compiler);
                        continue; // Avoid recursion
                    }
                }
                else if (node.Code.IsIntegerOnlyCompare())
                {
                    var             typeRef = node.Arguments[0].InferredType;
                    XTypeDefinition typeDef;
                    if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                    {
                        ConvertICmpArgument(node, 0, typeDef, compiler);
                    }
                    typeRef = node.Arguments[1].InferredType;
                    if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                    {
                        ConvertICmpArgument(node, 1, typeDef, compiler);
                    }
                }
                else if ((node.Code == AstCode.Switch) || (node.Code == AstCode.LookupSwitch))
                {
                    var             typeRef = node.Arguments[0].InferredType;
                    XTypeDefinition typeDef;
                    if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                    {
                        var isWide       = typeDef.GetEnumUnderlyingType().IsWide();
                        var enumValue    = new AstExpression(node.Arguments[0]);
                        var numericValue = new AstExpression(node.SourceLocation,
                                                             isWide ? AstCode.Enum_to_long : AstCode.Enum_to_int, null);
                        numericValue.InferredType = isWide ? typeSystem.Long : typeSystem.Int;
                        numericValue.Arguments.Add(enumValue);
                        node.Arguments.Clear();
                        node.Arguments.Add(numericValue);
                    }
                }
                else if (node.Code == AstCode.Brfalse)
                {
                    // brfalse(enum-expr) is used as "enum-expr == 0-valued-enum-value"
                    var             typeRef = node.Arguments[0].InferredType;
                    XTypeDefinition typeDef;
                    if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                    {
                        var isWide       = typeDef.GetEnumUnderlyingType().IsWide();
                        var enumValue    = new AstExpression(node.Arguments[0]);
                        var numericValue = new AstExpression(node.SourceLocation,
                                                             isWide ? AstCode.Enum_to_long : AstCode.Enum_to_int, null);
                        numericValue.InferredType = isWide ? typeSystem.Long : typeSystem.Int;
                        numericValue.Arguments.Add(enumValue);
                        node.Arguments.Clear();
                        node.Arguments.Add(numericValue);
                    }
                }

                // Note: no else here
                {
                    // Need to value type?
                    var inferredType = node.InferredType;
                    var expectedType = node.ExpectedType;

                    if ((inferredType != null) && (expectedType != null) && !inferredType.IsSame(expectedType))
                    {
                        // don't convert if either one is the abstract base class.
                        if (inferredType.IsInternalEnum() || expectedType.IsInternalEnum())
                        {
                            continue;
                        }

                        // don't convert if either one is a reference type
                        if (inferredType.IsByReference || expectedType.IsByReference)
                        {
                            continue;
                        }

                        XTypeDefinition expectedTypeDef;
                        if (expectedType.TryResolve(out expectedTypeDef) && expectedTypeDef.IsEnum)
                        {
                            // Enum expected, non-enum or different enum found
                            var underlyingType = expectedTypeDef.GetEnumUnderlyingType();
                            var isWide         = underlyingType.IsWide();

                            // If inferred type is another enum, convert to primitive first
                            if (inferredType.IsEnum())
                            {
                                var toPrimitive = new AstExpression(node)
                                {
                                    ExpectedType = null
                                };
                                node.Code = isWide ? AstCode.Enum_to_long : AstCode.Enum_to_int;
                                node.SetArguments(toPrimitive);
                                node.Operand = null;
                                node.SetType(isWide ? typeSystem.Long : typeSystem.Int);
                            }
                            else if (inferredType.IsPrimitive)
                            {
                                // Convert float/double to int/long before converting to enum
                                if (inferredType.IsDouble() || inferredType.IsFloat())
                                {
                                    var code  = isWide ? AstCode.Conv_I8 : AstCode.Conv_I4;
                                    var clone = new AstExpression(node)
                                    {
                                        ExpectedType = null
                                    };
                                    node.Code = code;
                                    node.SetArguments(clone);
                                    node.Operand = null;
                                    node.SetType(underlyingType);
                                }
                            }

                            var actualValue = new AstExpression(node)
                            {
                                ExpectedType = null
                            };
                            node.Code    = isWide ? AstCode.Long_to_enum : AstCode.Int_to_enum;
                            node.Operand = null;
                            node.SetArguments(actualValue);
                            node.SetType(expectedTypeDef);
                        }
                        else
                        {
                            XTypeDefinition inferredTypeDef;
                            if (inferredType.TryResolve(out inferredTypeDef) && inferredTypeDef.IsEnum)
                            {
                                if (!expectedType.IsSystemObject())
                                {
                                    // Enum found, non-enum expected
                                    var underlyingType = inferredTypeDef.GetEnumUnderlyingType();
                                    var isWide         = underlyingType.IsWide();

                                    var actualValue = new AstExpression(node)
                                    {
                                        ExpectedType = null
                                    };
                                    node.Code    = isWide ? AstCode.Enum_to_long : AstCode.Enum_to_int;
                                    node.Operand = null;
                                    node.SetArguments(actualValue);
                                    node.SetType(isWide ? typeSystem.Long : typeSystem.Int);
                                    ConvertIfNeeded(node, underlyingType);
                                }
                            }
                        }
                    }
                }
            }

            // Convert value of switch node
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstSwitch>())
            {
                var             typeRef = node.Condition.InferredType;
                XTypeDefinition typeDef;
                if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                {
                    var isWide  = typeDef.GetEnumUnderlyingType().IsWide();
                    var toValue = new AstExpression(node.Condition.SourceLocation, isWide ? AstCode.Enum_to_long : AstCode.Enum_to_int, null);
                    toValue.InferredType = isWide ? typeSystem.Long : typeSystem.Int;
                    toValue.Arguments.Add(node.Condition);
                    node.Condition = toValue;
                }
            }
        }
Example #32
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            foreach (var node in ast.GetExpressions())
            {
                switch (node.Code)
                {
                    // Optimize enum2int(ldsfld(enum-const))
                    //      and enum2int(int.to.enum(xxx))
                    case AstCode.Enum_to_int:
                    case AstCode.Enum_to_long:
                        {
                            var arg = node.Arguments[0];
                            XFieldReference fieldRef;
                            if (arg.Match(AstCode.Ldsfld, out fieldRef))
                            {
                                XFieldDefinition field;
                                object value;
                                if (fieldRef.TryResolve(out field) && field.IsStatic && field.DeclaringType.IsEnum && field.TryGetEnumValue(out value))
                                {
                                    // Replace with ldc_ix
                                    var wide = (node.Code == AstCode.Enum_to_long);
                                    node.SetCode(wide ? AstCode.Ldc_I8 : AstCode.Ldc_I4);
                                    node.Operand = wide ? (object)XConvert.ToLong(value) : XConvert.ToInt(value);
                                    node.Arguments.Clear();
                                }
                            }
                            else if (arg.Code == AstCode.Int_to_enum || arg.Code == AstCode.Long_to_enum)
                            {
                                var expectedType = node.ExpectedType;
                                node.CopyFrom(arg.Arguments[0]);
                                node.ExpectedType = expectedType;
                            }
                        }
                        break;
                    // optimize ceq/cne (int/long-to-enum(int), yyy)
                    case AstCode.Ceq:
                    case AstCode.Cne:
                    {
                        if (node.Arguments.Any(a=>IsToEnum(a.Code)))
                        {
                            // xx_to_enum is a quite costly operation when compared to enum-to-int,
                            // so convert this to an interger-only compare.
                            bool isLong = node.Arguments.Any(a => a.Code == AstCode.Long_to_enum);

                            foreach (var arg in node.Arguments)
                            {
                                if (IsToEnum(arg.Code))
                                {
                                    arg.CopyFrom(arg.Arguments[0]);
                                    arg.ExpectedType = isLong ? compiler.Module.TypeSystem.Long : compiler.Module.TypeSystem.Int;
                                }
                                else
                                {
                                    Debug.Assert(arg.GetResultType().IsEnum());
                                    var orig = new AstExpression(arg);
                                    var convert = new AstExpression(arg.SourceLocation,
                                        isLong ? AstCode.Enum_to_long : AstCode.Enum_to_int, null, orig);
                                    convert.ExpectedType = isLong ? compiler.Module.TypeSystem.Long : compiler.Module.TypeSystem.Int;
                                    arg.CopyFrom(convert);
                                }
                            }
                        }
                        break;
                    }
                }
            }
 
        }
Example #33
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            foreach (var node in ast.GetExpressions(AstCode.Call))
            {
                var method = node.Operand as XMethodReference;
                if ((method != null) && method.DeclaringType.GetElementType().IsNullableT())
                {
                    var git = (XGenericInstanceType)method.DeclaringType;
                    var type = git.GenericArguments[0];
                    if ((node.Arguments.Count == 2) && (method.Name == ".ctor"))
                    {
                        var target = node.Arguments[0];
                        var value = node.Arguments[1];

                        if (type.IsPrimitive)
                        {
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                    ConvertPrimitiveCtor(node, method, type, target, value);
                                    break;
                            }
                        }
                        else 
                        {
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                    ConvertOtherCtor(node, type, target, value);
                                    break;
                            }                            
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "get_HasValue"))
                    {
                        var target = node.Arguments[0];
                        switch (target.Code)
                        {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                            case AstCode.Ldloc:
                            case AstCode.Ldfld:
                            case AstCode.Ldsfld:
                            case AstCode.Ldelem_Ref:
                                ConvertHasValue(node, type, target);
                                break;
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "get_Value"))
                    {
                        if (type.IsPrimitive)
                        {
                            var target = node.Arguments[0];
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                case AstCode.Ldloc:
                                case AstCode.Ldfld:
                                case AstCode.Ldsfld:
                                case AstCode.Ldelem_Ref:
                                    ConvertPrimitiveGetValue(node, method, type, target, compiler.Module);
                                    break;
                            }
                        }
                        else 
                        {
                            var target = node.Arguments[0];
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                case AstCode.Ldloc:
                                case AstCode.Ldfld:
                                case AstCode.Ldsfld:
                                case AstCode.Ldelem_Ref:
                                    ConvertOtherGetValue(node, method, type, target, compiler.Module);
                                    break;
                            }
                        }
                    }
                    else if (method.Name == "GetValueOrDefault" && (node.Arguments.Count == 1 || node.Arguments.Count == 2))
                        
                    {
                        var target = node.Arguments[0];
                        switch (target.Code)
                        {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                            case AstCode.Ldloc:
                            case AstCode.Ldfld:
                            case AstCode.Ldsfld:
                            case AstCode.Ldelem_Ref:
                            {
                               ConvertGetValueOrDefault(node, type, compiler.Module);
                            }
                            break;
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "get_RawValue"))
                    {
                        var target = node.Arguments[0];
                        if (type.IsPrimitive)
                        {
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                    ConvertPrimitiveGetRawValue(node, type, target);
                                    break;
                            }
                        }
                        else 
                        {
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                    ConvertOtherGetRawValue(node, type, target);
                                    break;
                            }
                        }
                    }
                    else if (type.IsPrimitive || type.IsEnum())
                    {
                        // Convert ld_a to ld
                        foreach (var target in node.Arguments)
                        {
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                    ConvertLoad(target);
                                    break;
                            }
                        }
                    }
                }
            }

            foreach (var node in ast.GetExpressions(AstCode.Callvirt))
            {
                var method = node.Operand as XMethodReference;
                if ((method != null) && method.DeclaringType.IsSystemObject()
                    && method.Name == "ToString" && method.Parameters.Count == 0
                    && node.Arguments.Count == 1 && !method.Resolve().IsStatic)
                {
                    var type = node.Arguments[0].InferredType;
                    if (type != null && type.GetElementType().IsNullableT())
                    {
                        // redirect to Nullable.ToStringChecked() implementation
                        node.Operand = compiler.GetDot42InternalType("System", "Nullable").Resolve()
                            .Methods.First(m => m.Name == "ToStringChecked" && m.IsStatic && m.Parameters.Count == 1);
                        node.Code = AstCode.Call;
                    }
                }
            }

            foreach (var node in ast.GetExpressions(AstCode.Newobj))
            {
                var method = node.Operand as XMethodReference;
                if ((method != null) && method.DeclaringType.GetElementType().IsNullableT())
                {
                    var git = (XGenericInstanceType)method.DeclaringType;
                    var type = git.GenericArguments[0];
                    if ((node.Arguments.Count == 1) && (method.Name == ".ctor"))
                    {
                        var value = node.Arguments[0];

                        if (type.IsPrimitive)
                        {
                            ConvertPrimitiveNewObj(node, method, type, value);
                        }
                        else
                        {
                            ConvertOtherNewObj(node, method, type, value);
                        }
                    }                    
                }                
            }

            foreach (var node in ast.GetExpressions(AstCode.TypeOf))
            {
                var typeRef = node.Operand as XTypeReference;
                if (typeRef == null || !typeRef.IsGenericInstance)
                    continue;
                if (!typeRef.GetElementType().IsSystemNullable())
                    continue;
                var git = (XGenericInstanceType)typeRef;

                if (git.GenericArguments.Count != 1) // should not happen, but don't bother.
                    continue;

                var type = git.GenericArguments[0];

                node.Operand = type;
                node.Code = type.IsPrimitive ? AstCode.BoxedTypeOf : AstCode.NullableTypeOf;
            }
        }
Example #34
0
        private static void ConvertBeqBneWithConstToBrtrueBrfalse(AstNode ast)
        {
            // Convert beq/bne (cxx(x,x), 0/null/false/true) expressions to brtrue/brfalse
            foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.__Beq || x.Code == AstCode.__Bne_Un)).Reverse())
            {
                bool? reverse = ReverseCodeOnEqualCollapse(node);

                if (reverse == null)
                    continue;

                var expr = node.Arguments[0];

                if (node.Code == AstCode.__Bne_Un)
                    reverse = !reverse;

                var code = reverse.Value ? AstCode.Brfalse : AstCode.Brtrue;

                var newExpr = new AstExpression(expr.SourceLocation, code, node.Operand, expr);
                node.CopyFrom(newExpr, true);
            }
        }
Example #35
0
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            // combine ceq/cne (cxx(x,x), 0/null/false/true)  expressions
            var booleanType = compiler.Module.TypeSystem.Bool;
            foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Ceq || x.Code == AstCode.Cne)).Reverse())
            {
                var reverse = InvertComparisonIfPullComparisonUpToEquals(node, PullTarget.Comparison);

                if (reverse == null)
                    continue;

                if (node.Code == AstCode.Cne)
                    reverse = !reverse;

                var expr = node.Arguments[0];

                AstCode code = reverse.Value ? ReverseCode(expr.Code, expr.Arguments[0].GetResultType()) : expr.Code;

                var newExpr = new AstExpression(expr.SourceLocation, code, node.Operand, expr.Arguments[0], expr.Arguments[1])
                                    .SetType(booleanType);
                                        
                node.CopyFrom(newExpr, true);
            }

            // Convert beq/bne (cxx(x,x), 0/null/false/true) expressions to brtrue/brfalse
            ConvertBeqBneWithConstToBrtrueBrfalse(ast);

            // combine brtrue/brfalse (cxx(x,x)) expressions
            foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Brtrue) || (x.Code == AstCode.Brfalse)))
            {
                var expr = node.Arguments[0];
                if (expr.Code.IsCompare() && (expr.Arguments.Count == 2))
                {
                    var arg1 = expr.Arguments[0];
                    var arg2 = expr.Arguments[1];

                    var arg1Type = arg1.GetResultType();
                    var arg2Type = arg2.GetResultType();
                    if (CanPullComparisonUp(node.Code, arg1Type, arg2Type, PullTarget.Branch))
                    {
                        // Simplify
                        var code = (node.Code == AstCode.Brtrue) ? expr.Code : expr.Code.Reverse();

                        var newExpr = new AstExpression(expr.SourceLocation, code.ToBranch(), node.Operand, arg1, arg2);
                        node.CopyFrom(newExpr, true);
                    }
                    else if (CanPullComparisonUp(node.Code, arg1Type, arg2Type, PullTarget.Comparison))
                    {
                        // must be double/long/float argType
                        // simplify
                        var code = (node.Code == AstCode.Brtrue) ? expr.Code : ReverseCode(expr.Code, arg1Type);
                        bool needLBias = code == AstCode.Cgt || code == AstCode.Cge || code == AstCode.Cle_Un || code == AstCode.Clt_Un;
                        
                        var cmpCode = arg1Type.IsFloat() || arg1Type.IsDouble() 
                                        ? (needLBias? AstCode.CmpLFloat : AstCode.CmpGFloat)
                                        : AstCode.CmpLong;

                        var newExpr = new AstExpression(expr.SourceLocation, code.ToBranchZ(), node.Operand,
                                                new AstExpression(expr.SourceLocation, cmpCode, null, arg1, arg2));
                        node.CopyFrom(newExpr, true);
                    }
                }
            }

            // Convert beq/bne (cxx(x,x), 0/null/false/true) expressions to brtrue/brfalse
            // again.
            ConvertBeqBneWithConstToBrtrueBrfalse(ast);
        }
Example #36
0
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            // combine ceq/cne (cxx(x,x), 0/null/false/true)  expressions
            var booleanType = compiler.Module.TypeSystem.Bool;

            foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Ceq || x.Code == AstCode.Cne)).Reverse())
            {
                var reverse = InvertComparisonIfPullComparisonUpToEquals(node, PullTarget.Comparison);

                if (reverse == null)
                {
                    continue;
                }

                if (node.Code == AstCode.Cne)
                {
                    reverse = !reverse;
                }

                var expr = node.Arguments[0];

                AstCode code = reverse.Value ? ReverseCode(expr.Code, expr.Arguments[0].GetResultType()) : expr.Code;

                var newExpr = new AstExpression(expr.SourceLocation, code, node.Operand, expr.Arguments[0], expr.Arguments[1])
                              .SetType(booleanType);

                node.CopyFrom(newExpr, true);
            }

            // Convert beq/bne (cxx(x,x), 0/null/false/true) expressions to brtrue/brfalse
            ConvertBeqBneWithConstToBrtrueBrfalse(ast);

            // combine brtrue/brfalse (cxx(x,x)) expressions
            foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Brtrue) || (x.Code == AstCode.Brfalse)))
            {
                var expr = node.Arguments[0];
                if (expr.Code.IsCompare() && (expr.Arguments.Count == 2))
                {
                    var arg1 = expr.Arguments[0];
                    var arg2 = expr.Arguments[1];

                    var arg1Type = arg1.GetResultType();
                    var arg2Type = arg2.GetResultType();
                    if (CanPullComparisonUp(node.Code, arg1Type, arg2Type, PullTarget.Branch))
                    {
                        // Simplify
                        var code = (node.Code == AstCode.Brtrue) ? expr.Code : expr.Code.Reverse();

                        var newExpr = new AstExpression(expr.SourceLocation, code.ToBranch(), node.Operand, arg1, arg2);
                        node.CopyFrom(newExpr, true);
                    }
                    else if (CanPullComparisonUp(node.Code, arg1Type, arg2Type, PullTarget.Comparison))
                    {
                        // must be double/long/float argType
                        // simplify
                        var  code      = (node.Code == AstCode.Brtrue) ? expr.Code : ReverseCode(expr.Code, arg1Type);
                        bool needLBias = code == AstCode.Cgt || code == AstCode.Cge || code == AstCode.Cle_Un || code == AstCode.Clt_Un;

                        var cmpCode = arg1Type.IsFloat() || arg1Type.IsDouble()
                                        ? (needLBias? AstCode.CmpLFloat : AstCode.CmpGFloat)
                                        : AstCode.CmpLong;

                        var newExpr = new AstExpression(expr.SourceLocation, code.ToBranchZ(), node.Operand,
                                                        new AstExpression(expr.SourceLocation, cmpCode, null, arg1, arg2));
                        node.CopyFrom(newExpr, true);
                    }
                }
            }

            // Convert beq/bne (cxx(x,x), 0/null/false/true) expressions to brtrue/brfalse
            // again.
            ConvertBeqBneWithConstToBrtrueBrfalse(ast);
        }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Call) || (x.Code == AstCode.Calli) || (x.Code == AstCode.Callvirt)))
            {
                var method = (XMethodReference)node.Operand;
                bool processed = false;
                XMethodDefinition methodDef;

                if (method.TryResolve(out methodDef) && methodDef.DeclaringType.IsPrimitive)
                {
                    if (methodDef.IsConstructor &&  (node.Arguments.Count == 2))
                    {
                        // primitive.ctor(addressof_primitive, value) -> primitive.cast(value)
                        var locVar = node.Arguments[0].Operand;
                        node.Arguments.RemoveAt(0);
                        node.SetCode(AstCode.Stloc).SetType(node.Arguments[0].GetResultType()).Operand = locVar;
                        processed = true;
                    }
                    else if (methodDef.Name == "GetHashCode" && node.Arguments.Count == 1 && methodDef.HasThis)
                    {
                        // we try to avoid boxing.
                        var arg = node.Arguments[0];


                        switch (arg.Code)
                        {
                            case AstCode.AddressOf:
                                arg = arg.Arguments[0];
                                break;
                            case AstCode.Ldloca:
                                arg.SetCode(AstCode.Ldloc);
                                arg.SetType(arg.InferredType.ElementType);
                                break;
                            case AstCode.Ldflda:
                                arg.SetCode(AstCode.Ldfld);
                                arg.SetType(arg.InferredType.ElementType);
                                break;
                            case AstCode.Ldsflda:
                                arg.SetCode(AstCode.Ldsfld);
                                arg.SetType(arg.InferredType.ElementType);
                                break;
                            case AstCode.Ldelema:
                                arg.SetCode(AstCode.Ldelem_Any);
                                arg.SetType(arg.InferredType.ElementType);
                                break;
                        }

                        var type = arg.GetResultType();

                        if (type.IsBoolean()
                            || type.IsFloat() || type.IsDouble()
                            || type.IsInt64() || type.IsUInt64())
                        {
                            var ch = compiler.GetDot42InternalType("CompilerHelper").Resolve();

                            // these need special handling

                            var replMethod = ch.Methods.FirstOrDefault(m => m.Name == "GetHashCode" && m.IsStatic
                                                 && m.Parameters[0].ParameterType.IsSame(type, true));
                            if (replMethod != null)
                            {
                                node.Operand = replMethod;
                                node.SetCode(AstCode.Call);
                                node.Arguments.Clear();
                                node.Arguments.Add(arg);
                            }
                        }
                        else
                        {
                            // for the other primitive types, we just return the value itself.
                            node.CopyFrom(arg);
                            node.ExpectedType = compiler.Module.TypeSystem.Int;
                        }

                        processed = true;
                    }
                }

                if(!processed)
                {
                    for (var i = 0; i < node.Arguments.Count; i++)
                    {
                        ProcessArgument(node, method, i, currentMethod, compiler.Module);
                    }
                }
            }
        }
Example #38
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            foreach (var node in ast.GetExpressions(AstCode.Call))
            {
                var method = node.Operand as XMethodReference;
                if ((method != null) && method.DeclaringType.GetElementType().IsNullableT())
                {
                    var git = (XGenericInstanceType)method.DeclaringType;
                    var type = git.GenericArguments[0];
                    if ((node.Arguments.Count == 2) && (method.Name == ".ctor"))
                    {
                        var target = node.Arguments[0];
                        var value = node.Arguments[1];

                        if (type.IsPrimitive)
                        {
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                    ConvertPrimitiveCtor(node, method, type, target, value);
                                    break;
                            }
                        }
                        else 
                        {
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                    ConvertOtherCtor(node, type, target, value);
                                    break;
                            }                            
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "get_HasValue"))
                    {
                        var target = node.Arguments[0];
                        switch (target.Code)
                        {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                            case AstCode.Ldloc:
                            case AstCode.Ldfld:
                            case AstCode.Ldsfld:
                                ConvertHasValue(node, type, target);
                                break;
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "get_Value"))
                    {
                        if (type.IsPrimitive)
                        {
                            var target = node.Arguments[0];
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                case AstCode.Ldloc:
                                case AstCode.Ldfld:
                                case AstCode.Ldsfld:
                                    ConvertPrimitiveGetValue(node, method, type, target, compiler.Module);
                                    break;
                            }
                        }
                        else 
                        {
                            var target = node.Arguments[0];
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                case AstCode.Ldloc:
                                case AstCode.Ldfld:
                                case AstCode.Ldsfld:
                                    ConvertOtherGetValue(node, method, type, target, compiler.Module);
                                    break;
                            }
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "GetValueOrDefault"))
                    {
                        if (type.IsPrimitive)
                        {
                            var target = node.Arguments[0];
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                case AstCode.Ldloc:
                                case AstCode.Ldfld:
                                case AstCode.Ldsfld:
                                    ConvertPrimitiveGetValueOrDefault(node, method, type, target, compiler.Module);
                                    break;
                            }
                        }
                        else 
                        {
                            var target = node.Arguments[0];
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                case AstCode.Ldloc:
                                case AstCode.Ldfld:
                                case AstCode.Ldsfld:
                                    ConvertOtherGetValueOrDefault(node, type);
                                    break;
                            }
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "get_RawValue"))
                    {
                        var target = node.Arguments[0];
                        if (type.IsPrimitive)
                        {
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                    ConvertPrimitiveGetRawValue(node, type, target);
                                    break;
                            }
                        }
                        else 
                        {
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                    ConvertOtherGetRawValue(node, type, target);
                                    break;
                            }
                        }
                    }
                    else if (type.IsPrimitive || type.IsEnum())
                    {
                        // Convert ld_a to ld
                        foreach (var target in node.Arguments)
                        {
                            switch (target.Code)
                            {
                                case AstCode.Ldloca:
                                case AstCode.Ldflda:
                                case AstCode.Ldsflda:
                                    ConvertLoad(target);
                                    break;
                            }
                        }
                    }
                }
            } 

            foreach (var node in ast.GetExpressions(AstCode.Newobj))
            {
                var method = node.Operand as XMethodReference;
                if ((method != null) && method.DeclaringType.GetElementType().IsNullableT())
                {
                    var git = (XGenericInstanceType)method.DeclaringType;
                    var type = git.GenericArguments[0];
                    if ((node.Arguments.Count == 1) && (method.Name == ".ctor"))
                    {
                        var value = node.Arguments[0];

                        if (type.IsPrimitive)
                        {
                            ConvertPrimitiveNewObj(node, method, type, value);
                        }
                        else
                        {
                            ConvertOtherNewObj(node, method, type, value);
                        }
                    }                    
                }                
            }
        }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Call) || (x.Code == AstCode.Calli) || (x.Code == AstCode.Callvirt)))
            {
                var  method    = (XMethodReference)node.Operand;
                bool processed = false;
                XMethodDefinition methodDef;

                if (method.TryResolve(out methodDef) && methodDef.DeclaringType.IsPrimitive)
                {
                    if (methodDef.IsConstructor && (node.Arguments.Count == 2))
                    {
                        // primitive.ctor(addressof_primitive, value) -> primitive.cast(value)
                        var locVar = node.Arguments[0].Operand;
                        node.Arguments.RemoveAt(0);
                        node.SetCode(AstCode.Stloc).SetType(node.Arguments[0].GetResultType()).Operand = locVar;
                        processed = true;
                    }
                    else if (methodDef.Name == "GetHashCode" && node.Arguments.Count == 1 && methodDef.HasThis)
                    {
                        // we try to avoid boxing.
                        var arg = node.Arguments[0];


                        switch (arg.Code)
                        {
                        case AstCode.AddressOf:
                            arg = arg.Arguments[0];
                            break;

                        case AstCode.Ldloca:
                            arg.SetCode(AstCode.Ldloc);
                            arg.SetType(arg.InferredType.ElementType);
                            break;

                        case AstCode.Ldflda:
                            arg.SetCode(AstCode.Ldfld);
                            arg.SetType(arg.InferredType.ElementType);
                            break;

                        case AstCode.Ldsflda:
                            arg.SetCode(AstCode.Ldsfld);
                            arg.SetType(arg.InferredType.ElementType);
                            break;

                        case AstCode.Ldelema:
                            arg.SetCode(AstCode.Ldelem_Any);
                            arg.SetType(arg.InferredType.ElementType);
                            break;
                        }

                        var type = arg.GetResultType();

                        if (type.IsBoolean() ||
                            type.IsFloat() || type.IsDouble() ||
                            type.IsInt64() || type.IsUInt64())
                        {
                            var ch = compiler.GetDot42InternalType("CompilerHelper").Resolve();

                            // these need special handling

                            var replMethod = ch.Methods.FirstOrDefault(m => m.Name == "GetHashCode" && m.IsStatic &&
                                                                       m.Parameters[0].ParameterType.IsSame(type, true));
                            if (replMethod != null)
                            {
                                node.Operand = replMethod;
                                node.SetCode(AstCode.Call);
                                node.Arguments.Clear();
                                node.Arguments.Add(arg);
                            }
                        }
                        else
                        {
                            // for the other primitive types, we just return the value itself.
                            node.CopyFrom(arg);
                            node.ExpectedType = compiler.Module.TypeSystem.Int;
                        }

                        processed = true;
                    }
                }

                if (!processed)
                {
                    for (var i = 0; i < node.Arguments.Count; i++)
                    {
                        ProcessArgument(node, method, i, currentMethod, compiler.Module);
                    }
                }
            }
        }
Example #40
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            foreach (var node in ast.GetExpressions(AstCode.Call))
            {
                var method = node.Operand as XMethodReference;
                if ((method != null) && method.DeclaringType.GetElementType().IsNullableT())
                {
                    var git  = (XGenericInstanceType)method.DeclaringType;
                    var type = git.GenericArguments[0];
                    if ((node.Arguments.Count == 2) && (method.Name == ".ctor"))
                    {
                        var target = node.Arguments[0];
                        var value  = node.Arguments[1];

                        if (type.IsPrimitive)
                        {
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                                ConvertPrimitiveCtor(node, method, type, target, value);
                                break;
                            }
                        }
                        else
                        {
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                                ConvertOtherCtor(node, type, target, value);
                                break;
                            }
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "get_HasValue"))
                    {
                        var target = node.Arguments[0];
                        switch (target.Code)
                        {
                        case AstCode.Ldloca:
                        case AstCode.Ldflda:
                        case AstCode.Ldsflda:
                        case AstCode.Ldloc:
                        case AstCode.Ldfld:
                        case AstCode.Ldsfld:
                        case AstCode.Ldelem_Ref:
                            ConvertHasValue(node, type, target);
                            break;
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "get_Value"))
                    {
                        if (type.IsPrimitive)
                        {
                            var target = node.Arguments[0];
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                            case AstCode.Ldloc:
                            case AstCode.Ldfld:
                            case AstCode.Ldsfld:
                            case AstCode.Ldelem_Ref:
                                ConvertPrimitiveGetValue(node, method, type, target, compiler.Module);
                                break;
                            }
                        }
                        else
                        {
                            var target = node.Arguments[0];
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                            case AstCode.Ldloc:
                            case AstCode.Ldfld:
                            case AstCode.Ldsfld:
                            case AstCode.Ldelem_Ref:
                                ConvertOtherGetValue(node, method, type, target, compiler.Module);
                                break;
                            }
                        }
                    }
                    else if (method.Name == "GetValueOrDefault" && (node.Arguments.Count == 1 || node.Arguments.Count == 2))

                    {
                        var target = node.Arguments[0];
                        switch (target.Code)
                        {
                        case AstCode.Ldloca:
                        case AstCode.Ldflda:
                        case AstCode.Ldsflda:
                        case AstCode.Ldloc:
                        case AstCode.Ldfld:
                        case AstCode.Ldsfld:
                        case AstCode.Ldelem_Ref:
                        {
                            ConvertGetValueOrDefault(node, type, compiler.Module);
                        }
                        break;
                        }
                    }
                    else if ((node.Arguments.Count == 1) && (method.Name == "get_RawValue"))
                    {
                        var target = node.Arguments[0];
                        if (type.IsPrimitive)
                        {
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                                ConvertPrimitiveGetRawValue(node, type, target);
                                break;
                            }
                        }
                        else
                        {
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                                ConvertOtherGetRawValue(node, type, target);
                                break;
                            }
                        }
                    }
                    else if (type.IsPrimitive || type.IsEnum())
                    {
                        // Convert ld_a to ld
                        foreach (var target in node.Arguments)
                        {
                            switch (target.Code)
                            {
                            case AstCode.Ldloca:
                            case AstCode.Ldflda:
                            case AstCode.Ldsflda:
                                ConvertLoad(target);
                                break;
                            }
                        }
                    }
                }
            }

            foreach (var node in ast.GetExpressions(AstCode.Callvirt))
            {
                var method = node.Operand as XMethodReference;
                if ((method != null) && method.DeclaringType.IsSystemObject() &&
                    method.Name == "ToString" && method.Parameters.Count == 0 &&
                    node.Arguments.Count == 1 && !method.Resolve().IsStatic)
                {
                    var type = node.Arguments[0].InferredType;
                    if (type != null && type.GetElementType().IsNullableT())
                    {
                        // redirect to Nullable.ToStringChecked() implementation
                        node.Operand = compiler.GetDot42InternalType("System", "Nullable").Resolve()
                                       .Methods.First(m => m.Name == "ToStringChecked" && m.IsStatic && m.Parameters.Count == 1);
                        node.Code = AstCode.Call;
                    }
                }
            }

            foreach (var node in ast.GetExpressions(AstCode.Newobj))
            {
                var method = node.Operand as XMethodReference;
                if ((method != null) && method.DeclaringType.GetElementType().IsNullableT())
                {
                    var git  = (XGenericInstanceType)method.DeclaringType;
                    var type = git.GenericArguments[0];
                    if ((node.Arguments.Count == 1) && (method.Name == ".ctor"))
                    {
                        var value = node.Arguments[0];

                        if (type.IsPrimitive)
                        {
                            ConvertPrimitiveNewObj(node, method, type, value);
                        }
                        else
                        {
                            ConvertOtherNewObj(node, method, type, value);
                        }
                    }
                }
            }

            foreach (var node in ast.GetExpressions(AstCode.TypeOf))
            {
                var typeRef = node.Operand as XTypeReference;
                if (typeRef == null || !typeRef.IsGenericInstance)
                {
                    continue;
                }
                if (!typeRef.GetElementType().IsSystemNullable())
                {
                    continue;
                }
                var git = (XGenericInstanceType)typeRef;

                if (git.GenericArguments.Count != 1) // should not happen, but don't bother.
                {
                    continue;
                }

                var type = git.GenericArguments[0];

                node.Operand = type;
                node.Code    = type.IsPrimitive ? AstCode.BoxedTypeOf : AstCode.NullableTypeOf;
            }
        }
Example #41
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            var typeSystem = compiler.Module.TypeSystem;

            foreach (var node in ast.GetExpressions().Reverse())
            {
                if ((node.Code == AstCode.Ldc_I4) || (node.Code == AstCode.Ldc_I8))
                {
                    var typeRef = node.InferredType;
                    XTypeDefinition typeDef;
                    if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                    {
                        // Convert to ld-enum-value
                        XFieldDefinition field;
                        if (typeDef.TryGetEnumConstField(node.Operand, out field))
                        {
                            // Convert to ldsfld
                            node.Code = AstCode.Ldsfld;
                            node.Operand = field;
                            node.InferredType = typeDef;
                            node.ExpectedType = typeDef;
                        }
                        else
                        {
                            // Call Enum.GetValue(enumType, value)
                            var module = compiler.Module;
                            var valueType = (node.Code == AstCode.Ldc_I8)
                                                ? module.TypeSystem.Long
                                                : module.TypeSystem.Int;
                            var value = new AstExpression(node) {InferredType = valueType, ExpectedType = valueType};
                            node.Code = (node.Code == AstCode.Ldc_I8) ? AstCode.Long_to_enum : AstCode.Int_to_enum;
                            node.Operand = null;
                            node.InferredType = typeDef;
                            node.ExpectedType = typeDef;
                            node.Arguments.Clear();
                            node.Arguments.Add(value);
                        }
                    }
                }
                else if (node.Code.IsBinaryOperation())
                {
                    var typeRef = node.InferredType;
                    XTypeDefinition typeDef;
                    if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                    {
                        ConvertBinOp(node, typeDef, compiler);
                        continue; // Avoid recursion
                    }
                }
                else if (node.Code.IsIntegerOnlyCompare())
                {
                    var typeRef = node.Arguments[0].InferredType;
                    XTypeDefinition typeDef;
                    if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                    {
                        ConvertICmpArgument(node, 0, typeDef, compiler);
                    }
                    typeRef = node.Arguments[1].InferredType;
                    if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                    {
                        ConvertICmpArgument(node, 1, typeDef, compiler);
                    }
                }
                else if ((node.Code == AstCode.Switch) || (node.Code == AstCode.LookupSwitch))
                {
                    var typeRef = node.Arguments[0].InferredType;
                    XTypeDefinition typeDef;
                    if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                    {
                        var isWide = typeDef.GetEnumUnderlyingType().IsWide();
                        var enumValue = new AstExpression(node.Arguments[0]);
                        var numericValue = new AstExpression(node.SourceLocation,
                                                             isWide ? AstCode.Enum_to_long : AstCode.Enum_to_int, null);
                        numericValue.InferredType = isWide ? typeSystem.Long : typeSystem.Int;
                        numericValue.Arguments.Add(enumValue);
                        node.Arguments.Clear();
                        node.Arguments.Add(numericValue);
                    }
                }
                else if (node.Code == AstCode.Brfalse)
                {
                    // brfalse(enum-expr) is used as "enum-expr == 0-valued-enum-value"
                    var typeRef = node.Arguments[0].InferredType;
                    XTypeDefinition typeDef;
                    if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                    {
                        var isWide = typeDef.GetEnumUnderlyingType().IsWide();
                        var enumValue = new AstExpression(node.Arguments[0]);
                        var numericValue = new AstExpression(node.SourceLocation,
                                                             isWide ? AstCode.Enum_to_long : AstCode.Enum_to_int, null);
                        numericValue.InferredType = isWide ? typeSystem.Long : typeSystem.Int;
                        numericValue.Arguments.Add(enumValue);
                        node.Arguments.Clear();
                        node.Arguments.Add(numericValue);
                    }
                }

                // Note: no else here
                {
                    // Need to value type?
                    var inferredType = node.InferredType;
                    var expectedType = node.ExpectedType;

                    if ((inferredType != null) && (expectedType != null) && !inferredType.IsSame(expectedType))
                    {
                        // don't convert if either one is the abstract base class.
                        if (inferredType.IsInternalEnum() || expectedType.IsInternalEnum())
                            continue;

                        // don't convert if either one is a reference type
                        if (inferredType.IsByReference || expectedType.IsByReference)
                            continue;

                        XTypeDefinition expectedTypeDef;
                        if (expectedType.TryResolve(out expectedTypeDef) && expectedTypeDef.IsEnum)
                        {
                            // Enum expected, non-enum or different enum found
                            var underlyingType = expectedTypeDef.GetEnumUnderlyingType();
                            var isWide = underlyingType.IsWide();

                            // If inferred type is another enum, convert to primitive first
                            if (inferredType.IsEnum())
                            {
                                var toPrimitive = new AstExpression(node) { ExpectedType = null };
                                node.Code = isWide ? AstCode.Enum_to_long : AstCode.Enum_to_int;
                                node.SetArguments(toPrimitive);
                                node.Operand = null;
                                node.SetType(isWide ? typeSystem.Long : typeSystem.Int);
                            }
                            else if (inferredType.IsPrimitive)
                            {
                                // Convert float/double to int/long before converting to enum
                                if (inferredType.IsDouble() || inferredType.IsFloat())
                                {
                                    var code = isWide ? AstCode.Conv_I8 : AstCode.Conv_I4;
                                    var clone = new AstExpression(node) { ExpectedType = null };
                                    node.Code = code;
                                    node.SetArguments(clone);
                                    node.Operand = null;
                                    node.SetType(underlyingType);                                    
                                }
                            }

                            var actualValue = new AstExpression(node) {ExpectedType = null};
                            node.Code = isWide ? AstCode.Long_to_enum : AstCode.Int_to_enum;
                            node.Operand = null;
                            node.SetArguments(actualValue);
                            node.SetType(expectedTypeDef);
                        }
                        else
                        {
                            XTypeDefinition inferredTypeDef;
                            if (inferredType.TryResolve(out inferredTypeDef) && inferredTypeDef.IsEnum)
                            {
                                if (!expectedType.IsSystemObject())
                                {
                                    // Enum found, non-enum expected
                                    var underlyingType = inferredTypeDef.GetEnumUnderlyingType();
                                    var isWide = underlyingType.IsWide();

                                    var actualValue = new AstExpression(node) {ExpectedType = null};
                                    node.Code = isWide ? AstCode.Enum_to_long : AstCode.Enum_to_int;
                                    node.Operand = null;
                                    node.SetArguments(actualValue);
                                    node.SetType(isWide ? typeSystem.Long : typeSystem.Int);
                                    ConvertIfNeeded(node, underlyingType);
                                }
                            }
                        }
                    }
                }
            }

            // Convert value of switch node
            foreach (var node in ast.GetSelfAndChildrenRecursive<AstSwitch>())
            {
                var typeRef = node.Condition.InferredType;
                XTypeDefinition typeDef;
                if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsEnum)
                {
                    var isWide = typeDef.GetEnumUnderlyingType().IsWide();
                    var toValue = new AstExpression(node.Condition.SourceLocation, isWide ? AstCode.Enum_to_long : AstCode.Enum_to_int, null);
                    toValue.InferredType = isWide ? typeSystem.Long : typeSystem.Int;
                    toValue.Arguments.Add(node.Condition);
                    node.Condition = toValue;
                }                
            }
        }
Example #42
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            foreach (var node in ast.GetExpressions())
            {
                switch (node.Code)
                {
                // Optimize enum2int(ldsfld(enum-const))
                //      and enum2int(int.to.enum(xxx))
                case AstCode.Enum_to_int:
                case AstCode.Enum_to_long:
                {
                    var             arg = node.Arguments[0];
                    XFieldReference fieldRef;
                    if (arg.Match(AstCode.Ldsfld, out fieldRef))
                    {
                        XFieldDefinition field;
                        object           value;
                        if (fieldRef.TryResolve(out field) && field.IsStatic && field.DeclaringType.IsEnum && field.TryGetEnumValue(out value))
                        {
                            // Replace with ldc_ix
                            var wide = (node.Code == AstCode.Enum_to_long);
                            node.SetCode(wide ? AstCode.Ldc_I8 : AstCode.Ldc_I4);
                            node.Operand = wide ? (object)XConvert.ToLong(value) : XConvert.ToInt(value);
                            node.Arguments.Clear();
                        }
                    }
                    else if (arg.Code == AstCode.Int_to_enum || arg.Code == AstCode.Long_to_enum)
                    {
                        var expectedType = node.ExpectedType;
                        node.CopyFrom(arg.Arguments[0]);
                        node.ExpectedType = expectedType;
                    }
                }
                break;

                // optimize ceq/cne (int/long-to-enum(int), yyy)
                case AstCode.Ceq:
                case AstCode.Cne:
                {
                    if (node.Arguments.Any(a => IsToEnum(a.Code)))
                    {
                        // xx_to_enum is a quite costly operation when compared to enum-to-int,
                        // so convert this to an interger-only compare.
                        bool isLong = node.Arguments.Any(a => a.Code == AstCode.Long_to_enum);

                        foreach (var arg in node.Arguments)
                        {
                            if (IsToEnum(arg.Code))
                            {
                                arg.CopyFrom(arg.Arguments[0]);
                                arg.ExpectedType = isLong ? compiler.Module.TypeSystem.Long : compiler.Module.TypeSystem.Int;
                            }
                            else
                            {
                                Debug.Assert(arg.GetResultType().IsEnum());
                                var orig    = new AstExpression(arg);
                                var convert = new AstExpression(arg.SourceLocation,
                                                                isLong ? AstCode.Enum_to_long : AstCode.Enum_to_int, null, orig);
                                convert.ExpectedType = isLong ? compiler.Module.TypeSystem.Long : compiler.Module.TypeSystem.Int;
                                arg.CopyFrom(convert);
                            }
                        }
                    }
                    break;
                }
                }
            }
        }