diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index eb3a185a0..167184a26 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -76,6 +76,7 @@ namespace ICSharpCode.Decompiler.IL BitArray isBranchTarget; BlockContainer mainContainer; List instructionBuilder; + int currentInstructionStart; // Dictionary that stores stacks for each IL instruction Dictionary> stackByOffset; @@ -251,7 +252,7 @@ namespace ICSharpCode.Decompiler.IL /// void Warn(string message) { - Warnings.Add(string.Format("IL_{0:x4}: {1}", reader.Offset, message)); + Warnings.Add(string.Format("IL_{0:x4}: {1}", currentInstructionStart, message)); } ImmutableStack MergeStacks(ImmutableStack a, ImmutableStack b) @@ -382,6 +383,7 @@ namespace ICSharpCode.Decompiler.IL cancellationToken.ThrowIfCancellationRequested(); int start = reader.Offset; StoreStackForOffset(start, ref currentStack); + currentInstructionStart = start; ILInstruction decodedInstruction; try { decodedInstruction = DecodeInstruction(); @@ -1427,22 +1429,31 @@ namespace ICSharpCode.Decompiler.IL { var right = Pop(); var left = Pop(); - // make the implicit I4->I conversion explicit: - if (left.ResultType == StackType.I4 && right.ResultType == StackType.I) { - left = new Conv(left, PrimitiveType.I, false, Sign.None); - } else if (left.ResultType == StackType.I && right.ResultType == StackType.I4) { - right = new Conv(right, PrimitiveType.I, false, Sign.None); + + if (left.ResultType == StackType.O && right.ResultType.IsIntegerType()) { + // C++/CLI sometimes compares object references with integers. + if (right.ResultType == StackType.I4) { + // ensure we compare at least native integer size + right = new Conv(right, PrimitiveType.I, false, Sign.None); + } + left = new Conv(left, right.ResultType.ToPrimitiveType(), false, Sign.None); + } else if (right.ResultType == StackType.O && left.ResultType.IsIntegerType()) { + if (left.ResultType == StackType.I4) { + left = new Conv(left, PrimitiveType.I, false, Sign.None); + } + right = new Conv(right, left.ResultType.ToPrimitiveType(), false, Sign.None); } - + + // make implicit integer conversions explicit: + MakeExplicitConversion(sourceType: StackType.I4, targetType: StackType.I, conversionType: PrimitiveType.I); + MakeExplicitConversion(sourceType: StackType.I4, targetType: StackType.I8, conversionType: PrimitiveType.I8); + MakeExplicitConversion(sourceType: StackType.I, targetType: StackType.I8, conversionType: PrimitiveType.I8); + // Based on Table 4: Binary Comparison or Branch Operation if (left.ResultType.IsFloatType() && right.ResultType.IsFloatType()) { if (left.ResultType != right.ResultType) { // make the implicit F4->F8 conversion explicit: - if (left.ResultType == StackType.F4) { - left = new Conv(left, PrimitiveType.R8, false, Sign.Signed); - } else if (right.ResultType == StackType.F4) { - right = new Conv(right, PrimitiveType.R8, false, Sign.Signed); - } + MakeExplicitConversion(StackType.F4, StackType.F8, PrimitiveType.R8); } if (un) { // for floats, 'un' means 'unordered' @@ -1466,6 +1477,15 @@ namespace ICSharpCode.Decompiler.IL } return new Comp(kind, Sign.None, left, right); } + + void MakeExplicitConversion(StackType sourceType, StackType targetType, PrimitiveType conversionType) + { + if (left.ResultType == sourceType && right.ResultType == targetType) { + left = new Conv(left, conversionType, false, Sign.None); + } else if (left.ResultType == targetType && right.ResultType == sourceType) { + right = new Conv(right, conversionType, false, Sign.None); + } + } } bool IsInvalidBranch(int target) => target < 0 || target >= reader.Length; diff --git a/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs b/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs index fb226cda8..a90988b0f 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs @@ -131,6 +131,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms inst.InputType = StackType.I4; inst.Left.ReplaceWith(new LdLen(StackType.I4, array) { ILRange = inst.Left.ILRange }); inst.Right = rightWithoutConv; + } else if (inst.Left is Conv conv && conv.TargetType == PrimitiveType.I && conv.Argument.ResultType == StackType.O) { + // C++/CLI sometimes uses this weird comparison with null: + context.Step("comp(conv o->i (ldloc obj) == conv i4->i (ldc.i4 0))", inst); + // -> comp(ldloc obj == ldnull) + inst.InputType = StackType.O; + inst.Left = conv.Argument; + inst.Right = new LdNull { ILRange = inst.Right.ILRange }; + inst.Right.AddILRange(rightWithoutConv.ILRange); } }