Browse Source

Fix "Remove redundant comp(... != 0)" to avoid changing the value

When an IfInstruction was created with resultType=bool, because only
values 0 or 1 are possible, then we need to preserve this property in
transforms -- otherwise the added correctness test would fail.
pull/4091/head
Daniel Grunwald 4 days ago
parent
commit
c760a1d622
  1. 26
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/Comparisons.cs
  2. 4
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs
  3. 6
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
  4. 8
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

26
ICSharpCode.Decompiler.Tests/TestCases/Correctness/Comparisons.cs

@ -52,6 +52,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -52,6 +52,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Console.WriteLine(IsNull(new OverloadedOperators()));
Console.WriteLine(NullIs(new OverloadedOperators()));
Console.WriteLine(NullIsNot(new OverloadedOperators()));
Console.WriteLine("IntBranchInConditionSlot:");
IntBranchInConditionSlot(1, 0x100, false);
IntBranchInConditionSlot(0, 0x100, true);
NegatedIntBranchInConditionSlot(1, 0x100, false);
NegatedIntBranchInConditionSlot(0, 0x100, true);
return 0;
}
@ -92,6 +98,26 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -92,6 +98,26 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Console.WriteLine("uint: {0} == Id(-1) = {1}", i, i == Id(-1));
}
// The conditional has an int-valued true branch and a bool false branch, so it is
// compiled to an I4 value that the surrounding 'if' tests for non-zero. Converting
// that value to bool must keep the non-zero test: truncating it to 8 bits first
// loses every bit from 8 up, and flags = 0x100 then reads as false.
static void IntBranchInConditionSlot(int x, int flags, bool other)
{
if ((x > 0) ? (flags != 0) : other)
Console.WriteLine("true");
else
Console.WriteLine("false");
}
static void NegatedIntBranchInConditionSlot(int x, int flags, bool other)
{
if (!((x > 0) ? (flags != 0) : other))
Console.WriteLine("negated: false");
else
Console.WriteLine("negated: true");
}
static void Issue2398(long value)
{
if ((int)value != 0)

4
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs

@ -396,8 +396,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -396,8 +396,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (astBuilder.NameLookupMode == NameLookupMode.Type)
{
AstType outermostType = simpleType;
while (outermostType.Parent is AstType)
outermostType = (AstType)outermostType.Parent;
while (outermostType.Parent is AstType parent)
outermostType = parent;
if (outermostType.Parent is TypeReferenceExpression)
{
// ILSpy uses TypeReferenceExpression in expression context even when the C# parser

6
ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

@ -123,6 +123,12 @@ namespace ICSharpCode.Decompiler.IL @@ -123,6 +123,12 @@ namespace ICSharpCode.Decompiler.IL
}
}
output.Write(OpCode);
if (resultType != null)
{
output.Write(" [");
output.Write(resultType.ReflectionName);
output.Write(']');
}
output.Write(" (");
condition.WriteTo(output, options);
output.Write(") ");

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

@ -96,10 +96,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -96,10 +96,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return;
}
else if (inst.Kind == ComparisonKind.Inequality && inst.LiftingKind == ComparisonLiftingKind.None
&& inst.Right.MatchLdcI4(0) && (IfInstruction.IsInConditionSlot(inst) || inst.Left is Comp))
&& inst.Right.MatchLdcI4(0)
&& (inst.Left.InferType(context.TypeSystem).IsKnownType(KnownTypeCode.Boolean)
|| inst.Left.MatchLdcI4(0) || inst.Left.MatchLdcI4(1)))
{
// if (comp(x != 0)) ==> if (x)
// comp(comp(...) != 0) => comp(...)
// When `x` is known to be 0 or 1:
// `comp(x != 0) => x`
context.Step("Remove redundant comp(... != 0)", inst);
inst.Left.AddILRange(inst);
var left = inst.Left;

Loading…
Cancel
Save