Browse Source

Don't match sub.ovf in SwitchAnalysis.

pull/1296/head
Daniel Grunwald 7 years ago
parent
commit
f4613de2ba
  1. 24
      ICSharpCode.Decompiler/IL/ControlFlow/SwitchAnalysis.cs
  2. 31
      ICSharpCode.Decompiler/Util/CollectionExtensions.cs
  3. 3
      ICSharpCode.Decompiler/Util/LongSet.cs

24
ICSharpCode.Decompiler/IL/ControlFlow/SwitchAnalysis.cs

@ -233,21 +233,17 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
bool MatchSwitchVar(ILInstruction inst, out long sub) bool MatchSwitchVar(ILInstruction inst, out long sub)
{ {
if (inst.MatchBinaryNumericInstruction(BinaryNumericOperator.Sub, out var left, out var right) && right.MatchLdcI(out sub)) if (inst is BinaryNumericInstruction bn
return MatchSwitchVar(left); && bn.Operator == BinaryNumericOperator.Sub
&& !bn.CheckForOverflow && !bn.IsLifted
&& bn.Right.MatchLdcI(out sub))
{
return MatchSwitchVar(bn.Left);
}
sub = 0; sub = 0;
return MatchSwitchVar(inst); return MatchSwitchVar(inst);
} }
/// <summary>
/// Shifts a LongInterval, treating long.MinValue and long.MaxValue like float.Positive/NegativeInfinity
/// </summary>
LongInterval ShiftInterval(LongInterval interval, long offset)
{
return new LongInterval(
interval.Start == long.MinValue ? long.MinValue : interval.Start + offset,
interval.End == long.MinValue ? long.MinValue : interval.End + offset);
}
/// <summary> /// <summary>
/// Analyzes the boolean condition, returning the set of values of the interesting /// Analyzes the boolean condition, returning the set of values of the interesting
@ -256,11 +252,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
private bool AnalyzeCondition(ILInstruction condition, out LongSet trueValues) private bool AnalyzeCondition(ILInstruction condition, out LongSet trueValues)
{ {
if (condition is Comp comp && MatchSwitchVar(comp.Left, out var sub) && comp.Right.MatchLdcI(out long val)) { if (condition is Comp comp && MatchSwitchVar(comp.Left, out var sub) && comp.Right.MatchLdcI(out long val)) {
// if (comp(V OP val)) // if (comp((V - sub) OP val))
trueValues = MakeSetWhereComparisonIsTrue(comp.Kind, val, comp.Sign); trueValues = MakeSetWhereComparisonIsTrue(comp.Kind, val, comp.Sign);
if (sub != 0) trueValues = trueValues.AddOffset(sub);
trueValues = new LongSet(trueValues.Intervals.Select(i => ShiftInterval(i, sub)));
return true; return true;
} else if (MatchSwitchVar(condition)) { } else if (MatchSwitchVar(condition)) {
// if (ldloc V) --> branch for all values except 0 // if (ldloc V) --> branch for all values except 0

31
ICSharpCode.Decompiler/Util/CollectionExtensions.cs

@ -200,27 +200,28 @@ namespace ICSharpCode.Decompiler.Util
/// </summary> /// </summary>
public static IEnumerable<T> Merge<T>(this IEnumerable<T> input1, IEnumerable<T> input2, Comparison<T> comparison) public static IEnumerable<T> Merge<T>(this IEnumerable<T> input1, IEnumerable<T> input2, Comparison<T> comparison)
{ {
var enumA = input1.GetEnumerator(); using (var enumA = input1.GetEnumerator())
var enumB = input2.GetEnumerator(); using (var enumB = input2.GetEnumerator()) {
bool moreA = enumA.MoveNext(); bool moreA = enumA.MoveNext();
bool moreB = enumB.MoveNext(); bool moreB = enumB.MoveNext();
while (moreA && moreB) { while (moreA && moreB) {
if (comparison(enumA.Current, enumB.Current) <= 0) { if (comparison(enumA.Current, enumB.Current) <= 0) {
yield return enumA.Current;
moreA = enumA.MoveNext();
} else {
yield return enumB.Current;
moreB = enumB.MoveNext();
}
}
while (moreA) {
yield return enumA.Current; yield return enumA.Current;
moreA = enumA.MoveNext(); moreA = enumA.MoveNext();
} else { }
while (moreB) {
yield return enumB.Current; yield return enumB.Current;
moreB = enumB.MoveNext(); moreB = enumB.MoveNext();
} }
} }
while (moreA) {
yield return enumA.Current;
moreA = enumA.MoveNext();
}
while (moreB) {
yield return enumB.Current;
moreB = enumB.MoveNext();
}
} }
/// <summary> /// <summary>

3
ICSharpCode.Decompiler/Util/LongSet.cs

@ -203,6 +203,9 @@ namespace ICSharpCode.Decompiler.Util
/// </summary> /// </summary>
public LongSet AddOffset(long val) public LongSet AddOffset(long val)
{ {
if (val == 0) {
return this;
}
var newIntervals = new List<LongInterval>(Intervals.Length + 1); var newIntervals = new List<LongInterval>(Intervals.Length + 1);
foreach (var element in Intervals) { foreach (var element in Intervals) {
long newStart = unchecked(element.Start + val); long newStart = unchecked(element.Start + val);

Loading…
Cancel
Save