Browse Source

Partial decompilation of math operators with nullable arguments

pull/205/head
Pent Ploompuu 15 years ago
parent
commit
341f54833e
  1. 156
      ICSharpCode.Decompiler/ILAst/NullableOperators.cs

156
ICSharpCode.Decompiler/ILAst/NullableOperators.cs

@ -96,6 +96,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -96,6 +96,11 @@ namespace ICSharpCode.Decompiler.ILAst
{
return e.Code == this.code;
}
public override ILExpression BuildNew(ref PatternMatcher pm, ILExpression[] args)
{
return new ILExpression(code, null, args);
}
}
sealed class MethodPattern : Pattern
@ -122,7 +127,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -122,7 +127,7 @@ namespace ICSharpCode.Decompiler.ILAst
enum OperatorType
{
Equality, InEquality, Other
Equality, InEquality, Comparison, Unary, Other
}
sealed class OperatorPattern : Pattern
@ -131,7 +136,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -131,7 +136,7 @@ namespace ICSharpCode.Decompiler.ILAst
public OperatorPattern(params Pattern[] arguments) : base(arguments) { }
public OperatorPattern(OperatorType type, Pattern[] arguments)
public OperatorPattern(OperatorType type, params Pattern[] arguments)
: base(arguments)
{
this.type = type;
@ -154,8 +159,34 @@ namespace ICSharpCode.Decompiler.ILAst @@ -154,8 +159,34 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Clt_Un:
case ILCode.Cle:
case ILCode.Cle_Un:
if (type != OperatorType.Comparison) return false;
break;
case ILCode.Add:
case ILCode.Add_Ovf:
case ILCode.Add_Ovf_Un:
case ILCode.Sub:
case ILCode.Sub_Ovf:
case ILCode.Sub_Ovf_Un:
case ILCode.Mul:
case ILCode.Mul_Ovf:
case ILCode.Mul_Ovf_Un:
case ILCode.Div:
case ILCode.Div_Un:
case ILCode.Rem:
case ILCode.Rem_Un:
case ILCode.And:
case ILCode.Or:
case ILCode.Xor:
case ILCode.Shl:
case ILCode.Shr:
case ILCode.Shr_Un:
if (type != OperatorType.Other) return false;
break;
case ILCode.Not:
case ILCode.Neg:
case ILCode.LogicNot:
if (type != OperatorType.Unary) return false;
break;
case ILCode.Call:
var m = e.Operand as MethodReference;
if (m == null || m.HasThis || !m.HasParameters || m.Parameters.Count != base.Arguments.Length || !IsCustomOperator(m)) return false;
@ -178,7 +209,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -178,7 +209,7 @@ namespace ICSharpCode.Decompiler.ILAst
case "op_GreaterThanOrEqual":
case "op_LessThan":
case "op_LessThanOrEqual":
return type == OperatorType.Other;
return type == OperatorType.Comparison;
default: return false;
}
}
@ -236,6 +267,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -236,6 +267,7 @@ namespace ICSharpCode.Decompiler.ILAst
static readonly Pattern CeqHasValue = new ILPattern(ILCode.Ceq, VariableAHasValue, VariableBHasValue);
static readonly Pattern CneHasValue = new ILPattern(ILCode.Cne, VariableAHasValue, VariableBHasValue);
static readonly Pattern AndHasValue = new ILPattern(ILCode.And, VariableAHasValue, VariableBHasValue);
static readonly Pattern OperatorVariableAB = new OperatorPattern(VariableA, VariableB);
static readonly Pattern[] LoadValuesNN = new[] { VariableAGetValueOrDefault, VariableBGetValueOrDefault };
static OperatorPattern OperatorNN(OperatorType type)
@ -257,46 +289,63 @@ namespace ICSharpCode.Decompiler.ILAst @@ -257,46 +289,63 @@ namespace ICSharpCode.Decompiler.ILAst
static readonly Pattern[] Comparisons = new Pattern[] {
/* both operands nullable */
// == (Primitive, Decimal)
// == (primitive, decimal)
OperatorNN(OperatorType.Equality) & CeqHasValue,
// == (Struct)
// == (struct)
CeqHasValue & (!VariableAHasValue | OperatorNN(OperatorType.Equality)),
// != (Primitive, Decimal)
// != (primitive, decimal)
OperatorNN(OperatorType.InEquality) | CneHasValue,
// != (Struct)
// != (struct)
CneHasValue | (VariableAHasValue & OperatorNN(OperatorType.InEquality)),
// > , < , >= , <= (Primitive, Decimal)
OperatorNN(OperatorType.Other) & AndHasValue,
// > , < , >= , <= (Struct)
AndHasValue & OperatorNN(OperatorType.Other),
// > , < , >= , <= (primitive, decimal)
OperatorNN(OperatorType.Comparison) & AndHasValue,
// > , < , >= , <= (struct)
AndHasValue & OperatorNN(OperatorType.Comparison),
/* only first operand nullable */
// == (Primitive, Decimal)
// == (primitive, decimal)
OperatorNV(OperatorType.Equality) & VariableAHasValue,
// == (Struct)
// == (struct)
VariableAHasValue & OperatorNV(OperatorType.Equality),
// != (Primitive, Decimal)
// != (primitive, decimal)
OperatorNV(OperatorType.InEquality) | !VariableAHasValue,
// != (Struct)
// != (struct)
!VariableAHasValue | OperatorNV(OperatorType.InEquality),
// > , <, >= , <= (Primitive, Decimal)
OperatorNV(OperatorType.Other) & VariableAHasValue,
// > , < , >= , <= (Struct)
VariableAHasValue & OperatorNV(OperatorType.Other),
// > , <, >= , <= (primitive, decimal)
OperatorNV(OperatorType.Comparison) & VariableAHasValue,
// > , < , >= , <= (struct)
VariableAHasValue & OperatorNV(OperatorType.Comparison),
/* only second operand nullable */
// == (Primitive, Decimal)
// == (primitive, decimal)
OperatorVN(OperatorType.Equality) & VariableBHasValue,
// == (Struct)
// == (struct)
VariableBHasValue & OperatorVN(OperatorType.Equality),
// != (Primitive, Decimal)
// != (primitive, decimal)
OperatorVN(OperatorType.InEquality) | !VariableBHasValue,
// != (Struct)
// != (struct)
!VariableBHasValue | OperatorVN(OperatorType.InEquality),
// > , <, >= , <= (Primitive, Decimal)
OperatorVN(OperatorType.Other) & VariableBHasValue,
// > , < , >= , <= (Struct)
VariableBHasValue & OperatorVN(OperatorType.Other),
// > , <, >= , <= (primitive, decimal)
OperatorVN(OperatorType.Comparison) & VariableBHasValue,
// > , < , >= , <= (struct)
VariableBHasValue & OperatorVN(OperatorType.Comparison),
};
static readonly Pattern[] Other = new Pattern[] {
/* single nullable operand */
new ILPattern(ILCode.TernaryOp, VariableAHasValue, new MethodPattern(ILCode.Newobj, ".ctor", new OperatorPattern(OperatorType.Unary, VariableAGetValueOrDefault)), new ILPattern(ILCode.DefaultValue)),
new OperatorPattern(VariableA),
/* both operands nullable */
// & (bool)
new ILPattern(ILCode.TernaryOp, VariableAGetValueOrDefault | (!VariableBGetValueOrDefault & !VariableAHasValue), VariableB, VariableA),
new ILPattern(ILCode.And, VariableA, VariableB),
// | (bool)
new ILPattern(ILCode.TernaryOp, VariableAGetValueOrDefault | (!VariableBGetValueOrDefault & !VariableAHasValue), VariableA, VariableB),
new ILPattern(ILCode.Or, VariableA, VariableB),
// all other
new ILPattern(ILCode.TernaryOp, AndHasValue, new MethodPattern(ILCode.Newobj, ".ctor", OperatorNN(OperatorType.Other)), new ILPattern(ILCode.DefaultValue)),
OperatorVariableAB,
};
ILVariable A, B;
@ -313,30 +362,43 @@ namespace ICSharpCode.Decompiler.ILAst @@ -313,30 +362,43 @@ namespace ICSharpCode.Decompiler.ILAst
{
var args = new ILExpression[p.Arguments.Length];
for (int i = 0; i < args.Length; i++) args[i] = BuildNew(p.Arguments[i], old);
var res = p.BuildNew(ref this, args);
if (p is OperatorPattern) res.ILRanges = ILRange.OrderAndJoint(old.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(el => el.ILRanges));
return res;
return p.BuildNew(ref this, args);
}
static readonly Pattern OperatorVariableAB = new OperatorPattern(VariableA, VariableB);
public static bool Simplify(ILExpression expr)
{
if (expr.Code != ILCode.LogicAnd && expr.Code != ILCode.LogicOr) return false;
var ps = Comparisons;
for (int i = 0; i < ps.Length; i++) {
var pm = new PatternMatcher();
if (!pm.Match(ps[i], expr)) continue;
var n = pm.BuildNew(OperatorVariableAB, expr);
// the new expression is wrapped in a container so that negations aren't pushed through the comparison operation
expr.Code = ILCode.Wrap;
expr.Operand = null;
expr.Arguments.Clear();
expr.Arguments.Add(n);
expr.ILRanges.Clear();
expr.InferredType = n.InferredType;
return true;
if (expr.Code == ILCode.LogicAnd || expr.Code == ILCode.LogicOr) {
var ps = Comparisons;
for (int i = 0; i < ps.Length; i++) {
var pm = new PatternMatcher();
if (!pm.Match(ps[i], expr)) continue;
var n = pm.BuildNew(OperatorVariableAB, expr);
n.ILRanges = ILRange.OrderAndJoint(expr.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(el => el.ILRanges));
// the new expression is wrapped in a container so that negations aren't pushed through the comparison operation
expr.Code = ILCode.Wrap;
expr.Operand = null;
expr.Arguments.Clear();
expr.Arguments.Add(n);
expr.ILRanges.Clear();
expr.InferredType = n.InferredType;
return true;
}
} else if (expr.Code == ILCode.TernaryOp) {
var ps = Other;
for (int i = 0; i < ps.Length; i += 2) {
var pm = new PatternMatcher();
if (!pm.Match(ps[i], expr)) continue;
var n = pm.BuildNew(ps[i + 1], expr);
n.ILRanges = ILRange.OrderAndJoint(expr.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(el => el.ILRanges));
// the new expression is wrapped in a container so that negations aren't pushed through the comparison operation
expr.Code = ILCode.Wrap;
expr.Operand = null;
expr.Arguments.Clear();
expr.Arguments.Add(n);
expr.ILRanges.Clear();
expr.InferredType = n.InferredType;
return true;
}
}
return false;
}

Loading…
Cancel
Save