diff --git a/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs b/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs index 949d3e334..1a29a00d9 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs @@ -92,7 +92,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms // "logic.not(arg)" is sugar for "comp(arg != ldc.i4 0)" if (inst.MatchLogicNot(out var arg)) { - VisitLogicNot(inst, arg); + var toVisit = HandleLogicNot(inst, arg, context); + (toVisit ?? arg).AcceptVisitor(this); return; } else if (inst.Kind == ComparisonKind.Inequality && inst.LiftingKind == ComparisonLiftingKind.None @@ -238,9 +239,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms } } - void VisitLogicNot(Comp inst, ILInstruction arg) + /// + /// Handles combining negations with comparisons and logical operations. + /// Returns the instruction that `inst` was replaced with; or null is no transformation was made. + /// + static ILInstruction HandleLogicNot(Comp inst, ILInstruction arg, ILTransformContext context) { - ILInstruction lhs, rhs; if (arg is Comp comp) { if ((!comp.InputType.IsFloatType() && !comp.IsLifted) || comp.Kind.IsEqualityOrInequality()) @@ -250,10 +254,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms comp.AddILRange(inst); inst.ReplaceWith(comp); context.EndStep(comp); + return comp; } - comp.AcceptVisitor(this); } - else if (arg.MatchLogicAnd(out lhs, out rhs)) + else if (arg.MatchLogicAnd(out var lhs, out var rhs)) { // logic.not(if (lhs) rhs else ldc.i4 0) // ==> if (logic.not(lhs)) ldc.i4 1 else logic.not(rhs) @@ -266,7 +270,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms ifInst.FalseInst = Comp.LogicNot(rhs).WithILRange(inst); inst.ReplaceWith(ifInst); context.EndStep(ifInst); - ifInst.AcceptVisitor(this); + return ifInst; } else if (arg.MatchLogicOr(out lhs, out rhs)) { @@ -281,12 +285,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms ifInst.FalseInst = new LdcI4(0).WithILRange(ldc1); inst.ReplaceWith(ifInst); context.EndStep(ifInst); - ifInst.AcceptVisitor(this); - } - else - { - arg.AcceptVisitor(this); + return ifInst; } + return null; } protected internal override void VisitCall(Call inst) @@ -1027,6 +1028,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms inst.TestedOperand.AcceptVisitor(this); // Do not recurse into the sub-patterns: patterns are restricted to use only certain ILInstructions, // and arbitrary transforms might not stay within that allowed set of instructions. + foreach (var subPattern in inst.SubPatterns) + { + // However, we still need to simplify negations: + foreach (var potentialNegation in subPattern.Descendants.OfType()) + { + if (potentialNegation.MatchLogicNot(out var arg)) + { + HandleLogicNot(potentialNegation, arg, context); + } + } + } } } }