Browse Source

Partial decompilation of math operators with nullable arguments

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

130
ICSharpCode.Decompiler/ILAst/NullableOperators.cs

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

Loading…
Cancel
Save