From b75f217167fa3139bb09e7914bedb7bb087b6c8f Mon Sep 17 00:00:00 2001 From: LordJZ Date: Wed, 18 Feb 2015 15:01:40 +0300 Subject: [PATCH] Enhanced DivideBySize This fixes some redundant IntPtr casts. Some tests are still failing. Partially fixes #271 --- .../Ast/AstMethodBodyBuilder.cs | 58 +--------- .../ILAst/ILAstOptimizer.cs | 105 ++++++++++++++++++ 2 files changed, 110 insertions(+), 53 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 078fd4fa7..cba047841 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -291,16 +291,10 @@ namespace ICSharpCode.Decompiler.Ast { BinaryOperatorExpression boe; if (byteCode.InferredType is PointerType) { - if (byteCode.Arguments[0].ExpectedType is PointerType) { - arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType); - boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); - boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation); - } else if (byteCode.Arguments[1].ExpectedType is PointerType) { - arg1 = DivideBySize(arg1, ((PointerType)byteCode.InferredType).ElementType); - boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); + boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); + if (byteCode.Arguments[0].ExpectedType is PointerType || + byteCode.Arguments[1].ExpectedType is PointerType) { boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation); - } else { - boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); } } else { boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); @@ -314,12 +308,9 @@ namespace ICSharpCode.Decompiler.Ast { BinaryOperatorExpression boe; if (byteCode.InferredType is PointerType) { + boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); if (byteCode.Arguments[0].ExpectedType is PointerType) { - arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType); - boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); boe.WithAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation); - } else { - boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); } } else { boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); @@ -706,7 +697,7 @@ namespace ICSharpCode.Decompiler.Ast } return new StackAllocExpression { Type = AstBuilder.ConvertType(type), - CountExpression = DivideBySize(arg1, type) + CountExpression = arg1 }; } case ILCode.Mkrefany: @@ -902,45 +893,6 @@ namespace ICSharpCode.Decompiler.Ast } } - /// - /// Divides expr by the size of 'type'. - /// - Expression DivideBySize(Expression expr, TypeReference type) - { - CastExpression cast = expr as CastExpression; - if (cast != null && cast.Type is PrimitiveType && ((PrimitiveType)cast.Type).Keyword == "int") - expr = cast.Expression.Detach(); - - Expression sizeOfExpression; - switch (TypeAnalysis.GetInformationAmount(type)) { - case 1: - case 8: - sizeOfExpression = new PrimitiveExpression(1); - break; - case 16: - sizeOfExpression = new PrimitiveExpression(2); - break; - case 32: - sizeOfExpression = new PrimitiveExpression(4); - break; - case 64: - sizeOfExpression = new PrimitiveExpression(8); - break; - default: - sizeOfExpression = new SizeOfExpression { Type = AstBuilder.ConvertType(type) }; - break; - } - - BinaryOperatorExpression boe = expr as BinaryOperatorExpression; - if (boe != null && boe.Operator == BinaryOperatorType.Multiply && sizeOfExpression.IsMatch(boe.Right)) - return boe.Left.Detach(); - - if (sizeOfExpression.IsMatch(expr)) - return new PrimitiveExpression(1); - - return new BinaryOperatorExpression(expr, BinaryOperatorType.Divide, sizeOfExpression); - } - Expression MakeDefaultValue(TypeReference type) { TypeDefinition typeDef = type.Resolve(); diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index 6c8ccbe74..bd8543cf5 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -39,6 +39,7 @@ namespace ICSharpCode.Decompiler.ILAst PropertyAccessInstructions, SplitToMovableBlocks, TypeInference, + HandlePointerArithmetic, SimplifyShortCircuit, SimplifyTernaryOperator, SimplifyNullCoalescing, @@ -125,6 +126,9 @@ namespace ICSharpCode.Decompiler.ILAst // Types are needed for the ternary operator optimization TypeAnalysis.Run(context, method); + if (abortBeforeStep == ILAstOptimizationStep.HandlePointerArithmetic) return; + HandlePointerArithmetic(method); + foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { bool modified; do { @@ -664,6 +668,107 @@ namespace ICSharpCode.Decompiler.ILAst return combinedVariable; }); } + + static void HandlePointerArithmetic(ILNode method) + { + foreach (ILExpression expr in method.GetSelfAndChildrenRecursive()) { + List args = expr.Arguments; + switch (expr.Code) { + case ILCode.Localloc: + args[0] = DivideBySize(args[0], ((PointerType)expr.InferredType).ElementType); + break; + case ILCode.Add: + case ILCode.Add_Ovf: + case ILCode.Add_Ovf_Un: + if (expr.InferredType is PointerType) { + if (args[0].ExpectedType is PointerType) + args[1] = DivideBySize(args[1], ((PointerType)expr.InferredType).ElementType); + else if (args[1].ExpectedType is PointerType) + args[0] = DivideBySize(args[0], ((PointerType)expr.InferredType).ElementType); + } + break; + case ILCode.Sub: + case ILCode.Sub_Ovf: + case ILCode.Sub_Ovf_Un: + if (expr.InferredType is PointerType) { + if (args[0].ExpectedType is PointerType) + args[1] = DivideBySize(args[1], ((PointerType)expr.InferredType).ElementType); + } + break; + } + } + } + + static ILExpression UnwrapIntPtrCast(ILExpression expr) + { + if (expr.Code != ILCode.Conv_I && expr.Code != ILCode.Conv_U) + return expr; + + ILExpression arg = expr.Arguments[0]; + switch (arg.InferredType.MetadataType) { + case MetadataType.Byte: + case MetadataType.SByte: + case MetadataType.UInt16: + case MetadataType.Int16: + case MetadataType.UInt32: + case MetadataType.Int32: + case MetadataType.UInt64: + case MetadataType.Int64: + return arg; + } + + return expr; + } + + static ILExpression DivideBySize(ILExpression expr, TypeReference type) + { + expr = UnwrapIntPtrCast(expr); + + ILExpression sizeOfExpression; + switch (TypeAnalysis.GetInformationAmount(type)) { + case 1: + case 8: + sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 1); + break; + case 16: + sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 2); + break; + case 32: + sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 4); + break; + case 64: + sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 8); + break; + default: + sizeOfExpression = new ILExpression(ILCode.Sizeof, type); + break; + } + + if (expr.Code == ILCode.Mul || expr.Code == ILCode.Mul_Ovf || expr.Code == ILCode.Mul_Ovf_Un) { + ILExpression mulArg = expr.Arguments[1]; + if (mulArg.Code == sizeOfExpression.Code && sizeOfExpression.Operand.Equals(mulArg.Operand)) + return UnwrapIntPtrCast(expr.Arguments[0]); + } + + if (expr.Code == sizeOfExpression.Code) { + if (sizeOfExpression.Operand.Equals(expr.Operand)) + return new ILExpression(ILCode.Ldc_I4, 1); + + if (expr.Code == ILCode.Ldc_I4) { + int offsetInBytes = (int)expr.Operand; + int elementSize = (int)sizeOfExpression.Operand; + int offsetInElements = offsetInBytes / elementSize; + + // ensure integer division + if (offsetInElements * elementSize == offsetInBytes) { + expr.Operand = offsetInElements; + return expr; + } + } + } + + return new ILExpression(ILCode.Div_Un, null, expr, sizeOfExpression); + } public static void ReplaceVariables(ILNode node, Func variableMapping) {