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)
{