Browse Source

Enhanced DivideBySize

This fixes some redundant IntPtr casts. Some tests are still failing.

Partially fixes #271
pull/539/head
LordJZ 11 years ago
parent
commit
b75f217167
  1. 58
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 105
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

58
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -291,16 +291,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -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 @@ -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 @@ -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 @@ -902,45 +893,6 @@ namespace ICSharpCode.Decompiler.Ast
}
}
/// <summary>
/// Divides expr by the size of 'type'.
/// </summary>
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();

105
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -39,6 +39,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -39,6 +39,7 @@ namespace ICSharpCode.Decompiler.ILAst
PropertyAccessInstructions,
SplitToMovableBlocks,
TypeInference,
HandlePointerArithmetic,
SimplifyShortCircuit,
SimplifyTernaryOperator,
SimplifyNullCoalescing,
@ -125,6 +126,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -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<ILBlock>()) {
bool modified;
do {
@ -665,6 +669,107 @@ namespace ICSharpCode.Decompiler.ILAst @@ -665,6 +669,107 @@ namespace ICSharpCode.Decompiler.ILAst
});
}
static void HandlePointerArithmetic(ILNode method)
{
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
List<ILExpression> 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<ILVariable, ILVariable> variableMapping)
{
ILExpression expr = node as ILExpression;

Loading…
Cancel
Save