Browse Source

Eliminate the dedicated logic.not instruction, and treat it as syntax sugar similar to logic.and/logic.or.

'logic.not(arg)' is now represented using 'comp(arg == ldc.i4 0)'.
pull/870/head
Daniel Grunwald 8 years ago
parent
commit
919219524b
  1. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  2. 3
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.cs
  3. 5
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  4. 4
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  5. 2
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  6. 10
      ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs
  7. 29
      ICSharpCode.Decompiler/IL/ControlFlow/SymbolicExecution.cs
  8. 2
      ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs
  9. 4
      ICSharpCode.Decompiler/IL/ILReader.cs
  10. 53
      ICSharpCode.Decompiler/IL/Instructions.cs
  11. 2
      ICSharpCode.Decompiler/IL/Instructions.tt
  12. 14
      ICSharpCode.Decompiler/IL/Instructions/Comp.cs
  13. 60
      ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs
  14. 67
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  15. 2
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -118,7 +118,11 @@ namespace ICSharpCode.Decompiler.Tests @@ -118,7 +118,11 @@ namespace ICSharpCode.Decompiler.Tests
[Test, Ignore("Not implemented")]
public void LiftedOperators([ValueSource("defaultOptions")] CompilerOptions cscOptions)
{
Run(cscOptions: cscOptions);
try {
Run(cscOptions: cscOptions);
} catch (AssertionException) {
Assert.Ignore("Not implemented");
}
}
[Test, Ignore("Bad variable names; some if-else misdetected")]

3
ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.cs

@ -143,8 +143,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -143,8 +143,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return from c in this.customers
join o in this.orders on c.CustomerID equals o.CustomerID into co
let n = co.Count()
// should be n >= 10
where !(n < 10)
where n >= 10
select new {
Name = c.Name,
OrderCount = n

5
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -342,11 +342,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -342,11 +342,6 @@ namespace ICSharpCode.Decompiler.CSharp
.WithRR(new TypeOfResolveResult(compilation.FindType(new TopLevelTypeName("System", "RuntimeTypeHandle")), inst.Type));
}
protected internal override TranslatedExpression VisitLogicNot(LogicNot inst, TranslationContext context)
{
return TranslateCondition(inst.Argument, negate: true).WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitBitNot(BitNot inst, TranslationContext context)
{
var argument = Translate(inst.Argument);

4
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -381,9 +381,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -381,9 +381,9 @@ namespace ICSharpCode.Decompiler.CSharp
ILInstruction condition = null;
foreach (var c in conditions) {
if (condition == null)
condition = new LogicNot(c);
condition = Comp.LogicNot(c);
else
condition = IfInstruction.LogicAnd(new LogicNot(c), condition);
condition = IfInstruction.LogicAnd(Comp.LogicNot(c), condition);
}
return condition;
}

2
ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

@ -865,7 +865,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -865,7 +865,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
foreach (var tryFinally in function.Descendants.OfType<TryFinally>()) {
entryPoint = GetBodyEntryPoint(tryFinally.FinallyBlock as BlockContainer);
if (entryPoint?.Instructions[0] is IfInstruction ifInst) {
if (ifInst.Condition is LogicNot logicNot && logicNot.Argument.MatchLdLoc(doFinallyBodies)) {
if (ifInst.Condition.MatchLogicNot(out var logicNotArg) && logicNotArg.MatchLdLoc(doFinallyBodies)) {
context.Step("Remove if(doFinallyBodies) from try-finally", tryFinally);
// condition will always be false now that we're using 'await' instructions
entryPoint.Instructions.RemoveAt(0);

10
ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs

@ -98,7 +98,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -98,7 +98,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
block.Instructions[block.Instructions.Count - 1] = ifInst.TrueInst;
ifInst.TrueInst = exitInst;
exitInst = block.Instructions.Last();
ifInst.Condition = new LogicNot(ifInst.Condition);
ifInst.Condition = Comp.LogicNot(ifInst.Condition);
}
ILInstruction trueExitInst;
@ -119,7 +119,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -119,7 +119,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// "if (...) { if (nestedCondition) goto exitPoint; ... } goto exitPoint;"
// -> "if (... && !nestedCondition) { ... } goto exitPoint;"
context.Step("Combine 'if (cond1 && !cond2)' in then-branch", ifInst);
ifInst.Condition = IfInstruction.LogicAnd(ifInst.Condition, new LogicNot(nestedCondition));
ifInst.Condition = IfInstruction.LogicAnd(ifInst.Condition, Comp.LogicNot(nestedCondition));
targetBlock.Instructions.RemoveAt(0);
// Update targetBlock label now that we've removed the first instruction
if (targetBlock.Instructions.FirstOrDefault()?.ILRange.IsEmpty == false) {
@ -137,7 +137,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -137,7 +137,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// (only if end-point of 'falseInst...' is unreachable)
context.Step("Invert nested condition to reduce number of gotos", ifInst);
var nestedIfInst = (IfInstruction)targetBlock.Instructions[0];
nestedIfInst.Condition = new LogicNot(nestedCondition);
nestedIfInst.Condition = Comp.LogicNot(nestedCondition);
nestedTrueBlock.Instructions.RemoveAt(nestedTrueBlock.Instructions.Count - 1); // remove nested goto exitPoint;
// remove falseInsts from outer block
var falseInsts = targetBlock.Instructions.Skip(1).ToArray();
@ -197,7 +197,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -197,7 +197,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
var oldTrue = ifInst.TrueInst;
ifInst.TrueInst = ifInst.FalseInst;
ifInst.FalseInst = new Nop { ILRange = oldTrue.ILRange };
ifInst.Condition = new LogicNot(ifInst.Condition);
ifInst.Condition = Comp.LogicNot(ifInst.Condition);
// After swapping, it's possible that we can introduce a short-circuit operator:
Block trueBlock = ifInst.TrueInst as Block;
@ -218,7 +218,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -218,7 +218,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
var oldTrue = ifInst.TrueInst;
ifInst.TrueInst = ifInst.FalseInst;
ifInst.FalseInst = oldTrue;
ifInst.Condition = new LogicNot(ifInst.Condition);
ifInst.Condition = Comp.LogicNot(ifInst.Condition);
}
}

29
ICSharpCode.Decompiler/IL/ControlFlow/SymbolicExecution.cs

@ -142,18 +142,23 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -142,18 +142,23 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} else if (inst is Comp comp) {
var left = Eval(comp.Left);
var right = Eval(comp.Right);
if (left.Type != SymbolicValueType.State || right.Type != SymbolicValueType.IntegerConstant)
return Failed;
// bool: (state + left.Constant == right.Constant)
LongSet trueSums = SwitchAnalysis.MakeSetWhereComparisonIsTrue(comp.Kind, right.Constant, comp.Sign);
// symbolic value is true iff trueSums.Contains(state + left.Constant)
LongSet trueStates = trueSums.AddOffset(unchecked(-left.Constant));
// symbolic value is true iff trueStates.Contains(state)
return new SymbolicValue(SymbolicValueType.StateInSet, trueStates);
} else if (inst is LogicNot logicNot) {
SymbolicValue val = Eval(logicNot.Argument).AsBool();
if (val.Type == SymbolicValueType.StateInSet) {
return new SymbolicValue(SymbolicValueType.StateInSet, val.ValueSet.Invert());
if (left.Type == SymbolicValueType.State && right.Type == SymbolicValueType.IntegerConstant) {
// bool: (state + left.Constant == right.Constant)
LongSet trueSums = SwitchAnalysis.MakeSetWhereComparisonIsTrue(comp.Kind, right.Constant, comp.Sign);
// symbolic value is true iff trueSums.Contains(state + left.Constant)
LongSet trueStates = trueSums.AddOffset(unchecked(-left.Constant));
// symbolic value is true iff trueStates.Contains(state)
return new SymbolicValue(SymbolicValueType.StateInSet, trueStates);
} else if (left.Type == SymbolicValueType.StateInSet && right.Type == SymbolicValueType.IntegerConstant) {
if (comp.Kind == ComparisonKind.Equality && right.Constant == 0) {
// comp((x in set) == 0) ==> x not in set
return new SymbolicValue(SymbolicValueType.StateInSet, left.ValueSet.Invert());
} else if (comp.Kind == ComparisonKind.Inequality && right.Constant != 0) {
// comp((x in set) != 0) => x in set
return new SymbolicValue(SymbolicValueType.StateInSet, left.ValueSet);
} else {
return Failed;
}
} else {
return Failed;
}

2
ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs

@ -995,7 +995,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -995,7 +995,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
foreach (var tryFinally in function.Descendants.OfType<TryFinally>()) {
entryPoint = AsyncAwaitDecompiler.GetBodyEntryPoint(tryFinally.FinallyBlock as BlockContainer);
if (entryPoint?.Instructions[0] is IfInstruction ifInst) {
if (ifInst.Condition is LogicNot logicNot && logicNot.Argument.MatchLdLoc(skipFinallyBodies)) {
if (ifInst.Condition.MatchLogicNot(out var logicNotArg) && logicNotArg.MatchLdLoc(skipFinallyBodies)) {
context.Step("Remove if (skipFinallyBodies) from try-finally", tryFinally);
// condition will always be true now that we're using 'yield' instructions
entryPoint.Instructions[0] = ifInst.TrueInst;

4
ICSharpCode.Decompiler/IL/ILReader.cs

@ -1133,7 +1133,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1133,7 +1133,7 @@ namespace ICSharpCode.Decompiler.IL
if (left.ResultType == StackType.F && right.ResultType == StackType.F) {
if (un) {
// for floats, 'un' means 'unordered'
return new LogicNot(new Comp(kind.Negate(), Sign.None, left, right));
return Comp.LogicNot(new Comp(kind.Negate(), Sign.None, left, right));
} else {
return new Comp(kind, Sign.None, left, right);
}
@ -1189,7 +1189,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1189,7 +1189,7 @@ namespace ICSharpCode.Decompiler.IL
break;
default:
if (negate) {
condition = new LogicNot(condition);
condition = Comp.LogicNot(condition);
}
break;
}

53
ICSharpCode.Decompiler/IL/Instructions.cs

@ -43,8 +43,6 @@ namespace ICSharpCode.Decompiler.IL @@ -43,8 +43,6 @@ namespace ICSharpCode.Decompiler.IL
Block,
/// <summary>A region where a pinned variable is used (initial representation of future fixed statement).</summary>
PinnedRegion,
/// <summary>Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).</summary>
LogicNot,
/// <summary>Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.</summary>
BinaryNumericInstruction,
/// <summary>Common instruction for compound assignments.</summary>
@ -833,34 +831,6 @@ namespace ICSharpCode.Decompiler.IL @@ -833,34 +831,6 @@ namespace ICSharpCode.Decompiler.IL
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).</summary>
public sealed partial class LogicNot : UnaryInstruction
{
public LogicNot(ILInstruction argument) : base(OpCode.LogicNot, argument)
{
}
public override StackType ResultType { get { return StackType.I4; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLogicNot(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLogicNot(this);
}
public override T AcceptVisitor<C, T>(ILVisitor<C, T> visitor, C context)
{
return visitor.VisitLogicNot(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LogicNot;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.</summary>
public sealed partial class BinaryNumericInstruction : BinaryInstruction
@ -4223,10 +4193,6 @@ namespace ICSharpCode.Decompiler.IL @@ -4223,10 +4193,6 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitLogicNot(LogicNot inst)
{
Default(inst);
}
protected internal virtual void VisitBinaryNumericInstruction(BinaryNumericInstruction inst)
{
Default(inst);
@ -4501,10 +4467,6 @@ namespace ICSharpCode.Decompiler.IL @@ -4501,10 +4467,6 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitLogicNot(LogicNot inst)
{
return Default(inst);
}
protected internal virtual T VisitBinaryNumericInstruction(BinaryNumericInstruction inst)
{
return Default(inst);
@ -4779,10 +4741,6 @@ namespace ICSharpCode.Decompiler.IL @@ -4779,10 +4741,6 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst, context);
}
protected internal virtual T VisitLogicNot(LogicNot inst, C context)
{
return Default(inst, context);
}
protected internal virtual T VisitBinaryNumericInstruction(BinaryNumericInstruction inst, C context)
{
return Default(inst, context);
@ -5031,7 +4989,6 @@ namespace ICSharpCode.Decompiler.IL @@ -5031,7 +4989,6 @@ namespace ICSharpCode.Decompiler.IL
"BlockContainer",
"Block",
"PinnedRegion",
"logic.not",
"binary",
"compound",
"bit.not",
@ -5135,16 +5092,6 @@ namespace ICSharpCode.Decompiler.IL @@ -5135,16 +5092,6 @@ namespace ICSharpCode.Decompiler.IL
body = default(ILInstruction);
return false;
}
public bool MatchLogicNot(out ILInstruction argument)
{
var inst = this as LogicNot;
if (inst != null) {
argument = inst.Argument;
return true;
}
argument = default(ILInstruction);
return false;
}
public bool MatchBitNot(out ILInstruction argument)
{
var inst = this as BitNot;

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -63,8 +63,6 @@ @@ -63,8 +63,6 @@
new ChildInfo("init") { CanInlineInto = true },
new ChildInfo("body")
})),
new OpCode("logic.not", "Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).",
ResultType("I4"), Unary),
new OpCode("binary", "Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.",
CustomClassName("BinaryNumericInstruction"), Binary, CustomWriteTo, CustomConstructor, CustomComputeFlags,
MatchCondition("CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator && IsLifted == o.IsLifted")),

14
ICSharpCode.Decompiler/IL/Instructions/Comp.cs

@ -20,6 +20,8 @@ using System; @@ -20,6 +20,8 @@ using System;
using System.Diagnostics;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL
{
public enum ComparisonKind : byte
@ -132,7 +134,7 @@ namespace ICSharpCode.Decompiler.IL @@ -132,7 +134,7 @@ namespace ICSharpCode.Decompiler.IL
/// For lifted comparisons, this is the underlying input type.
/// </summary>
public StackType InputType;
/// <summary>
/// If this is an integer comparison, specifies the sign used to interpret the integers.
/// </summary>
@ -198,6 +200,16 @@ namespace ICSharpCode.Decompiler.IL @@ -198,6 +200,16 @@ namespace ICSharpCode.Decompiler.IL
Right.WriteTo(output);
output.Write(')');
}
public static Comp LogicNot(ILInstruction arg)
{
return new Comp(ComparisonKind.Equality, Sign.None, arg, new LdcI4(0));
}
public static Comp LogicNot(ILInstruction arg, Interval ilrange)
{
return new Comp(ComparisonKind.Equality, Sign.None, arg, new LdcI4(0)) { ILRange = ilrange };
}
}
}

60
ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs

@ -257,6 +257,22 @@ namespace ICSharpCode.Decompiler.IL @@ -257,6 +257,22 @@ namespace ICSharpCode.Decompiler.IL
return false;
}
/// <summary>
/// Matches an logical negation.
/// </summary>
public bool MatchLogicNot(out ILInstruction arg)
{
if (this is Comp comp && comp.Kind == ComparisonKind.Equality
&& comp.LiftingKind == ComparisonLiftingKind.None
&& comp.Right.MatchLdcI4(0))
{
arg = comp.Left;
return true;
}
arg = null;
return false;
}
public bool MatchTryCatchHandler(out ILVariable variable)
{
var inst = this as TryCatchHandler;
@ -273,23 +289,19 @@ namespace ICSharpCode.Decompiler.IL @@ -273,23 +289,19 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public bool MatchCompEquals(out ILInstruction left, out ILInstruction right)
{
ComparisonKind op;
Comp comp;
if (this is LogicNot logicNot) {
op = ComparisonKind.Inequality;
comp = logicNot.Argument as Comp;
} else {
op = ComparisonKind.Equality;
comp = this as Comp;
}
if (comp != null && comp.Kind == op) {
if (this.MatchLogicNot(out var arg) && arg is Comp nestedComp && nestedComp.Kind == ComparisonKind.Inequality && !nestedComp.IsLifted) {
left = nestedComp.Left;
right = nestedComp.Right;
return true;
} else if (this is Comp comp && comp.Kind == ComparisonKind.Equality && !comp.IsLifted) {
left = comp.Left;
right = comp.Right;
return true;
} else {
left = null;
right = null;
return false;
}
left = null;
right = null;
return false;
}
/// <summary>
@ -297,23 +309,19 @@ namespace ICSharpCode.Decompiler.IL @@ -297,23 +309,19 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public bool MatchCompNotEquals(out ILInstruction left, out ILInstruction right)
{
ComparisonKind op;
Comp comp;
if (this is LogicNot logicNot) {
op = ComparisonKind.Equality;
comp = logicNot.Argument as Comp;
} else {
op = ComparisonKind.Inequality;
comp = this as Comp;
}
if (comp != null && comp.Kind == op) {
if (this.MatchLogicNot(out var arg) && arg is Comp nestedComp && nestedComp.Kind == ComparisonKind.Equality && !nestedComp.IsLifted) {
left = nestedComp.Left;
right = nestedComp.Right;
return true;
} else if (this is Comp comp && comp.Kind == ComparisonKind.Inequality && !comp.IsLifted) {
left = comp.Left;
right = comp.Right;
return true;
} else {
left = null;
right = null;
return false;
}
left = null;
right = null;
return false;
}
public bool MatchLdsFld(IField field)

67
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -52,8 +52,36 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -52,8 +52,36 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// we know those were already handled previously.
}
static bool IsInConditionSlot(ILInstruction inst)
{
var slot = inst.SlotInfo;
if (slot == IfInstruction.ConditionSlot)
return true;
if (slot == IfInstruction.TrueInstSlot || slot == IfInstruction.FalseInstSlot || slot == NullCoalescingInstruction.FallbackInstSlot)
return IsInConditionSlot(inst.Parent);
if (inst.Parent.MatchLogicNot(out _))
return true;
return false;
}
protected internal override void VisitComp(Comp inst)
{
// "logic.not(arg)" is sugar for "comp(arg != ldc.i4 0)"
if (inst.MatchLogicNot(out var arg)) {
VisitLogicNot(inst, arg);
return;
} else if (inst.Kind == ComparisonKind.Inequality && inst.LiftingKind == ComparisonLiftingKind.None
&& inst.Right.MatchLdcI4(0) && (IsInConditionSlot(inst) || inst.Left is Comp)
) {
// if (comp(x != 0)) ==> if (x)
// comp(comp(...) != 0) => comp(...)
context.Step("Remove redundant comp(... != 0)", inst);
inst.Left.AddILRange(inst.ILRange);
inst.ReplaceWith(inst.Left);
inst.Left.AcceptVisitor(this);
return;
}
base.VisitComp(inst);
if (inst.IsLifted) {
return;
@ -94,9 +122,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -94,9 +122,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (inst.Kind == ComparisonKind.GreaterThan) {
context.Step("comp.unsigned(left > ldc.i4 0) => comp(left != ldc.i4 0)", inst);
inst.Kind = ComparisonKind.Inequality;
VisitComp(inst);
return;
} else if (inst.Kind == ComparisonKind.LessThanOrEqual) {
context.Step("comp.unsigned(left <= ldc.i4 0) => comp(left == ldc.i4 0)", inst);
inst.Kind = ComparisonKind.Equality;
VisitComp(inst);
return;
}
}
}
@ -137,17 +169,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -137,17 +169,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
protected internal override void VisitLogicNot(LogicNot inst)
void VisitLogicNot(Comp inst, ILInstruction arg)
{
ILInstruction arg, lhs, rhs;
if (inst.Argument.MatchLogicNot(out arg)) {
context.Step("logic.not(logic.not(arg)) => arg", inst);
Debug.Assert(arg.ResultType == StackType.I4);
arg.AddILRange(inst.ILRange);
arg.AddILRange(inst.Argument.ILRange);
inst.ReplaceWith(arg);
arg.AcceptVisitor(this);
} else if (inst.Argument is Comp comp) {
ILInstruction lhs, rhs;
if (arg is Comp comp) {
if ((comp.InputType != StackType.F && !comp.IsLifted) || comp.Kind.IsEqualityOrInequality()) {
context.Step("push negation into comparison", inst);
comp.Kind = comp.Kind.Negate();
@ -155,32 +180,32 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -155,32 +180,32 @@ namespace ICSharpCode.Decompiler.IL.Transforms
inst.ReplaceWith(comp);
}
comp.AcceptVisitor(this);
} else if (inst.Argument.MatchLogicAnd(out lhs, out rhs)) {
} else if (arg.MatchLogicAnd(out lhs, out rhs)) {
// logic.not(if (lhs) rhs else ldc.i4 0)
// ==> if (logic.not(lhs)) ldc.i4 1 else logic.not(rhs)
context.Step("push negation into logic.and", inst);
IfInstruction ifInst = (IfInstruction)inst.Argument;
IfInstruction ifInst = (IfInstruction)arg;
var ldc0 = ifInst.FalseInst;
Debug.Assert(ldc0.MatchLdcI4(0));
ifInst.Condition = new LogicNot(lhs) { ILRange = inst.ILRange };
ifInst.Condition = Comp.LogicNot(lhs, inst.ILRange);
ifInst.TrueInst = new LdcI4(1) { ILRange = ldc0.ILRange };
ifInst.FalseInst = new LogicNot(rhs) { ILRange = inst.ILRange };
ifInst.FalseInst = Comp.LogicNot(rhs, inst.ILRange);
inst.ReplaceWith(ifInst);
ifInst.AcceptVisitor(this);
} else if (inst.Argument.MatchLogicOr(out lhs, out rhs)) {
} else if (arg.MatchLogicOr(out lhs, out rhs)) {
// logic.not(if (lhs) ldc.i4 1 else rhs)
// ==> if (logic.not(lhs)) logic.not(rhs) else ldc.i4 0)
context.Step("push negation into logic.or", inst);
IfInstruction ifInst = (IfInstruction)inst.Argument;
IfInstruction ifInst = (IfInstruction)arg;
var ldc1 = ifInst.TrueInst;
Debug.Assert(ldc1.MatchLdcI4(1));
ifInst.Condition = new LogicNot(lhs) { ILRange = inst.ILRange };
ifInst.TrueInst = new LogicNot(rhs) { ILRange = inst.ILRange };
ifInst.Condition = Comp.LogicNot(lhs, inst.ILRange);
ifInst.TrueInst = Comp.LogicNot(rhs, inst.ILRange);
ifInst.FalseInst = new LdcI4(0) { ILRange = ldc1.ILRange };
inst.ReplaceWith(ifInst);
ifInst.AcceptVisitor(this);
} else {
inst.Argument.AcceptVisitor(this);
arg.AcceptVisitor(this);
}
}
@ -286,7 +311,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -286,7 +311,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var t = inst.TrueInst;
inst.TrueInst = inst.FalseInst;
inst.FalseInst = t;
inst.Condition = new LogicNot(inst.Condition);
inst.Condition = Comp.LogicNot(inst.Condition);
}
base.VisitIfInstruction(inst);
@ -309,7 +334,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -309,7 +334,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILInstruction value1, value2;
if (trueInst.Instructions[0].MatchStLoc(out v, out value1) && falseInst.Instructions[0].MatchStLoc(v, out value2)) {
context.Step("conditional operator", inst);
var newIf = new IfInstruction(new LogicNot(inst.Condition), value2, value1);
var newIf = new IfInstruction(Comp.LogicNot(inst.Condition), value2, value1);
newIf.ILRange = inst.ILRange;
inst.ReplaceWith(new StLoc(v, newIf));
return newIf;

2
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -287,7 +287,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -287,7 +287,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case OpCode.Leave:
return parent == next;
case OpCode.IfInstruction:
while (parent.OpCode == OpCode.LogicNot) {
while (parent.MatchLogicNot(out _)) {
parent = parent.Parent;
}
return parent == next;

Loading…
Cancel
Save