Skip to content

WIP preincrement improvements #3472

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4946,5 +4946,21 @@ public void Issue1779(int value)
CustomStruct2 customStruct = GetStruct();
customStruct.IntProp += value;
}

public static string PreincrementWithMethodCall(int value)
{
return (++value).ToString();
}

#if CS72
public static string PreincrementWithInParameter(int value)
{
PreincrementWithInParameter_Helper(++value);
return value.ToString();
}
public static void PreincrementWithInParameter_Helper(in int value)
{
}
#endif
}
}
80 changes: 79 additions & 1 deletion ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ void IStatementTransform.Run(Block block, int pos, StatementTransformContext con
if (context.Settings.IntroduceIncrementAndDecrement)
{
if (TransformPostIncDecOperatorWithInlineStore(block, pos)
|| TransformPostIncDecOperator(block, pos))
|| TransformPostIncDecOperator(block, pos)
|| TransformPreIncDecOperatorWithInlineStore(block, pos))
{
// again, new top-level stloc might need inlining:
context.RequestRerun();
Expand Down Expand Up @@ -844,6 +845,83 @@ bool IsDuplicatedAddressComputation(ILInstruction storeTarget, ILInstruction loa
}
}

/// <code>
/// stloc l(stloc target(binary.add(ldloc target, ldc.i4 1)))
/// </code>
bool TransformPreIncDecOperatorWithInlineStore(Block block, int pos)
{
var store = block.Instructions[pos];
if (!IsCompoundStore(store, out var targetType1, out var value1, context.TypeSystem))
{
return false;
}
if (!IsCompoundStore(value1, out var targetType2, out var value2, context.TypeSystem))
{
return false;
}
if (targetType1 != targetType2)
return false;
var targetType = targetType1;
var stloc_outer = store as StLoc;
var stloc_inner = value1 as StLoc;
LdLoc ldloc;
var binary = UnwrapSmallIntegerConv(value2, out var conv) as BinaryNumericInstruction;
if (binary != null && (binary.Right.MatchLdcI(1) || binary.Right.MatchLdcF4(1) || binary.Right.MatchLdcF8(1)))
{
if (!(binary.Operator == BinaryNumericOperator.Add || binary.Operator == BinaryNumericOperator.Sub))
return false;

if (conv is not null)
{
var primitiveType = targetType.ToPrimitiveType();
if (primitiveType.GetSize() == conv.TargetType.GetSize() && primitiveType.GetSign() != conv.TargetType.GetSign())
targetType = SwapSign(targetType, context.TypeSystem);
}

if (!ValidateCompoundAssign(binary, conv, targetType, context.Settings))
return false;
ldloc = binary.Left as LdLoc;
}
else if (value2 is Call operatorCall && operatorCall.Method.IsOperator && operatorCall.Arguments.Count == 1)
{
if (!(operatorCall.Method.Name == "op_Increment" || operatorCall.Method.Name == "op_Decrement"))
return false;
if (operatorCall.IsLifted)
return false; // TODO: add tests and think about whether nullables need special considerations
ldloc = operatorCall.Arguments[0] as LdLoc;
}
else
{
return false;
}
if (stloc_outer == null)
return false;
if (stloc_inner == null)
return false;
if (ldloc == null)
return false;
if (!(stloc_outer.Variable.Kind == VariableKind.Local || stloc_outer.Variable.Kind == VariableKind.StackSlot))
return false;
if (!IsMatchingCompoundLoad(ldloc, stloc_inner, out var target, out var targetKind, out var finalizeMatch))
return false;
if (IsImplicitTruncation(stloc_outer.Value, stloc_outer.Variable.Type, context.TypeSystem))
return false;
context.Step(nameof(TransformPreIncDecOperatorWithInlineStore), store);
finalizeMatch?.Invoke(context);
if (binary != null)
{
block.Instructions[pos] = new StLoc(stloc_outer.Variable, new NumericCompoundAssign(
binary, target, targetKind, binary.Right, targetType, CompoundEvalMode.EvaluatesToNewValue));
}
else
{
Call operatorCall = (Call)value2;
block.Instructions[pos] = new StLoc(stloc_outer.Variable, new UserDefinedCompoundAssign(
operatorCall.Method, CompoundEvalMode.EvaluatesToNewValue, target, targetKind, new LdcI4(1)));
}
return true;
}

/// <code>
/// stobj(target, binary.add(stloc l(ldobj(target)), ldc.i4 1))
/// where target is pure and does not use 'l', and the 'stloc l' does not truncate
Expand Down
Loading