Skip to content

Commit ec58d57

Browse files
committed
#3465: Fix bugs in comp.o handling.
1 parent 052466f commit ec58d57

File tree

4 files changed

+28
-11
lines changed

4 files changed

+28
-11
lines changed

ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3465.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ private static Program GetProgram()
1616
private static bool Test3465()
1717
{
1818
Program program = GetProgram();
19-
Program program2 = programNull;
20-
return System.Runtime.CompilerServices.Unsafe.As<Program, UIntPtr>(ref program) > System.Runtime.CompilerServices.Unsafe.As<Program, UIntPtr>(ref program2);
19+
return System.Runtime.CompilerServices.Unsafe.As<Program, UIntPtr>(ref program) > System.Runtime.CompilerServices.Unsafe.As<Program, UIntPtr>(ref programNull);
2120
}
2221
}
2322
}

ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,15 +1112,15 @@ TranslatedExpression TranslateComp(Comp inst)
11121112
{
11131113
// Unsafe.As<object, UIntPtr>(ref left) op Unsafe.As<object, UIntPtr>(ref right)
11141114
// TTo Unsafe.As<TFrom, TTo>(ref TFrom source)
1115-
var uintptr = compilation.FindType(KnownTypeCode.UIntPtr);
1115+
var integerType = compilation.FindType(inst.Sign == Sign.Signed ? KnownTypeCode.IntPtr : KnownTypeCode.UIntPtr);
11161116
left = WrapInUnsafeAs(left, inst.Left);
11171117
right = WrapInUnsafeAs(right, inst.Right);
11181118

11191119
TranslatedExpression WrapInUnsafeAs(TranslatedExpression expr, ILInstruction inst)
11201120
{
11211121
var type = expr.Type;
11221122
expr = WrapInRef(expr, new ByReferenceType(type));
1123-
return CallUnsafeIntrinsic("As", [expr], uintptr, typeArguments: [type, uintptr]);
1123+
return CallUnsafeIntrinsic("As", [expr], integerType, typeArguments: [type, integerType]);
11241124
}
11251125
}
11261126
return new BinaryOperatorExpression(left.Expression, op, right.Expression)

ICSharpCode.Decompiler/IL/ILReader.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,11 +1248,14 @@ DecodedInstruction DecodeInstruction()
12481248
}
12491249
}
12501250

1251-
StackType PeekStackType(int i = 0)
1251+
StackType PeekStackType()
12521252
{
1253-
if (expressionStack.Count > i)
1254-
return expressionStack[^(i + 1)].ResultType;
1255-
return currentStack.Skip(i).FirstOrDefault()?.StackType ?? StackType.Unknown;
1253+
if (expressionStack.Count > 0)
1254+
return expressionStack.Last().ResultType;
1255+
if (currentStack.IsEmpty)
1256+
return StackType.Unknown;
1257+
else
1258+
return currentStack.Peek().StackType;
12561259
}
12571260

12581261
sealed class CollectStackVariablesVisitor : ILVisitor<ILInstruction>
@@ -1842,8 +1845,7 @@ DecodedInstruction DecodeCallIndirect()
18421845

18431846
ILInstruction Comparison(ComparisonKind kind, bool un = false)
18441847
{
1845-
var stackType = PeekStackType();
1846-
if (!kind.IsEqualityOrInequality() && stackType == StackType.O && stackType == PeekStackType(1))
1848+
if (!kind.IsEqualityOrInequality() && PeekStackType() == StackType.O)
18471849
{
18481850
FlushExpressionStack();
18491851
}

ICSharpCode.Decompiler/IL/Instructions/Comp.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,23 @@ internal override bool CanInlineIntoSlot(int childIndex, ILInstruction expressio
235235
// ExpressionBuilder translates comp.o(a op b) for op not in (==, !=) into
236236
// Unsafe.As(ref a) op Unsafe.As(ref b), which requires that a and b are variables
237237
// and not expressions. Returning false in those cases prevents inlining.
238-
return kind.IsEqualityOrInequality() || this.InputType != StackType.O;
238+
// However if one of the arguments is LdNull, then we don't need the Unsafe.As trickery, and can always inline.
239+
if (kind.IsEqualityOrInequality() || this.InputType != StackType.O)
240+
{
241+
// OK, won't need Unsafe.As.
242+
return true;
243+
}
244+
if (expressionBeingMoved is LdLoc || expressionBeingMoved.MatchLdsFld(out _))
245+
{
246+
// OK, can use variable/field name with Unsafe.As(ref x)
247+
return true;
248+
}
249+
if (Sign != Sign.Signed && (expressionBeingMoved is LdNull || Left is LdNull || Right is LdNull))
250+
{
251+
// OK, this is the "compare with null" special case that doesn't need Unsafe.As()
252+
return true;
253+
}
254+
return false;
239255
}
240256
}
241257
}

0 commit comments

Comments
 (0)