Skip to content

Commit 6c00c13

Browse files
Fix #3465: Translate comp.o(a op b) if op not in (==, !=) into Unsafe.As<object, UIntPtr>(ref a) op Unsafe.As<object, UIntPtr>(ref b)
1 parent 582e847 commit 6c00c13

File tree

3 files changed

+33
-7
lines changed

3 files changed

+33
-7
lines changed

ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,21 @@ TranslatedExpression TranslateComp(Comp inst)
11081108
left = left.ConvertTo(inputType, this);
11091109
right = right.ConvertTo(inputType, this);
11101110
}
1111+
else if (inst.InputType == StackType.O)
1112+
{
1113+
// Unsafe.As<object, UIntPtr>(ref left) op Unsafe.As<object, UIntPtr>(ref right)
1114+
// TTo Unsafe.As<TFrom, TTo>(ref TFrom source)
1115+
var uintptr = compilation.FindType(KnownTypeCode.UIntPtr);
1116+
left = WrapInUnsafeAs(left, inst.Left);
1117+
right = WrapInUnsafeAs(right, inst.Right);
1118+
1119+
TranslatedExpression WrapInUnsafeAs(TranslatedExpression expr, ILInstruction inst)
1120+
{
1121+
var type = expr.Type;
1122+
expr = WrapInRef(expr, new ByReferenceType(type));
1123+
return CallUnsafeIntrinsic("As", [expr], uintptr, typeArguments: [type, uintptr]);
1124+
}
1125+
}
11111126
return new BinaryOperatorExpression(left.Expression, op, right.Expression)
11121127
.WithILInstruction(inst)
11131128
.WithRR(new OperatorResolveResult(compilation.FindType(TypeCode.Boolean),

ICSharpCode.Decompiler/IL/ILReader.cs

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

1251-
StackType PeekStackType()
1251+
StackType PeekStackType(int i = 0)
12521252
{
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;
1253+
if (expressionStack.Count > i)
1254+
return expressionStack[^(i + 1)].ResultType;
1255+
return currentStack.Skip(i).FirstOrDefault()?.StackType ?? StackType.Unknown;
12591256
}
12601257

12611258
sealed class CollectStackVariablesVisitor : ILVisitor<ILInstruction>
@@ -1845,6 +1842,12 @@ DecodedInstruction DecodeCallIndirect()
18451842

18461843
ILInstruction Comparison(ComparisonKind kind, bool un = false)
18471844
{
1845+
var stackType = PeekStackType();
1846+
if (!kind.IsEqualityOrInequality() && stackType == StackType.O && stackType == PeekStackType(1))
1847+
{
1848+
FlushExpressionStack();
1849+
}
1850+
18481851
var right = Pop();
18491852
var left = Pop();
18501853
// left will run before right, thus preserving the evaluation order

ICSharpCode.Decompiler/IL/Instructions/Comp.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,5 +229,13 @@ public static Comp LogicNot(ILInstruction arg, bool isLifted)
229229
var liftingKind = isLifted ? ComparisonLiftingKind.ThreeValuedLogic : ComparisonLiftingKind.None;
230230
return new Comp(ComparisonKind.Equality, liftingKind, StackType.I4, Sign.None, arg, new LdcI4(0));
231231
}
232+
233+
internal override bool CanInlineIntoSlot(int childIndex, ILInstruction expressionBeingMoved)
234+
{
235+
// ExpressionBuilder translates comp.o(a op b) for op not in (==, !=) into
236+
// Unsafe.As(ref a) op Unsafe.As(ref b), which requires that a and b are variables
237+
// and not expressions. Returning false in those cases prevents inlining.
238+
return kind.IsEqualityOrInequality() || this.InputType != StackType.O;
239+
}
232240
}
233241
}

0 commit comments

Comments
 (0)