Skip to content

Commit f72319e

Browse files
committed
WIP preincrement improvements
1 parent 0d8a85c commit f72319e

File tree

2 files changed

+95
-1
lines changed

2 files changed

+95
-1
lines changed

ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4946,5 +4946,21 @@ public void Issue1779(int value)
49464946
CustomStruct2 customStruct = GetStruct();
49474947
customStruct.IntProp += value;
49484948
}
4949+
4950+
public static string PreincrementWithMethodCall(int value)
4951+
{
4952+
return (++value).ToString();
4953+
}
4954+
4955+
#if CS72
4956+
public static string PreincrementWithInParameter(int value)
4957+
{
4958+
PreincrementWithInParameter_Helper(++value);
4959+
return value.ToString();
4960+
}
4961+
public static void PreincrementWithInParameter_Helper(in int value)
4962+
{
4963+
}
4964+
#endif
49494965
}
49504966
}

ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ void IStatementTransform.Run(Block block, int pos, StatementTransformContext con
5454
if (context.Settings.IntroduceIncrementAndDecrement)
5555
{
5656
if (TransformPostIncDecOperatorWithInlineStore(block, pos)
57-
|| TransformPostIncDecOperator(block, pos))
57+
|| TransformPostIncDecOperator(block, pos)
58+
|| TransformPreIncDecOperatorWithInlineStore(block, pos))
5859
{
5960
// again, new top-level stloc might need inlining:
6061
context.RequestRerun();
@@ -844,6 +845,83 @@ bool IsDuplicatedAddressComputation(ILInstruction storeTarget, ILInstruction loa
844845
}
845846
}
846847

848+
/// <code>
849+
/// stloc l(stloc target(binary.add(ldloc target, ldc.i4 1)))
850+
/// </code>
851+
bool TransformPreIncDecOperatorWithInlineStore(Block block, int pos)
852+
{
853+
var store = block.Instructions[pos];
854+
if (!IsCompoundStore(store, out var targetType1, out var value1, context.TypeSystem))
855+
{
856+
return false;
857+
}
858+
if (!IsCompoundStore(value1, out var targetType2, out var value2, context.TypeSystem))
859+
{
860+
return false;
861+
}
862+
if (targetType1 != targetType2)
863+
return false;
864+
var targetType = targetType1;
865+
var stloc_outer = store as StLoc;
866+
var stloc_inner = value1 as StLoc;
867+
LdLoc ldloc;
868+
var binary = UnwrapSmallIntegerConv(value2, out var conv) as BinaryNumericInstruction;
869+
if (binary != null && (binary.Right.MatchLdcI(1) || binary.Right.MatchLdcF4(1) || binary.Right.MatchLdcF8(1)))
870+
{
871+
if (!(binary.Operator == BinaryNumericOperator.Add || binary.Operator == BinaryNumericOperator.Sub))
872+
return false;
873+
874+
if (conv is not null)
875+
{
876+
var primitiveType = targetType.ToPrimitiveType();
877+
if (primitiveType.GetSize() == conv.TargetType.GetSize() && primitiveType.GetSign() != conv.TargetType.GetSign())
878+
targetType = SwapSign(targetType, context.TypeSystem);
879+
}
880+
881+
if (!ValidateCompoundAssign(binary, conv, targetType, context.Settings))
882+
return false;
883+
ldloc = binary.Left as LdLoc;
884+
}
885+
else if (value2 is Call operatorCall && operatorCall.Method.IsOperator && operatorCall.Arguments.Count == 1)
886+
{
887+
if (!(operatorCall.Method.Name == "op_Increment" || operatorCall.Method.Name == "op_Decrement"))
888+
return false;
889+
if (operatorCall.IsLifted)
890+
return false; // TODO: add tests and think about whether nullables need special considerations
891+
ldloc = operatorCall.Arguments[0] as LdLoc;
892+
}
893+
else
894+
{
895+
return false;
896+
}
897+
if (stloc_outer == null)
898+
return false;
899+
if (stloc_inner == null)
900+
return false;
901+
if (ldloc == null)
902+
return false;
903+
if (!(stloc_outer.Variable.Kind == VariableKind.Local || stloc_outer.Variable.Kind == VariableKind.StackSlot))
904+
return false;
905+
if (!IsMatchingCompoundLoad(ldloc, stloc_inner, out var target, out var targetKind, out var finalizeMatch))
906+
return false;
907+
if (IsImplicitTruncation(stloc_outer.Value, stloc_outer.Variable.Type, context.TypeSystem))
908+
return false;
909+
context.Step(nameof(TransformPreIncDecOperatorWithInlineStore), store);
910+
finalizeMatch?.Invoke(context);
911+
if (binary != null)
912+
{
913+
block.Instructions[pos] = new StLoc(stloc_outer.Variable, new NumericCompoundAssign(
914+
binary, target, targetKind, binary.Right, targetType, CompoundEvalMode.EvaluatesToNewValue));
915+
}
916+
else
917+
{
918+
Call operatorCall = (Call)value2;
919+
block.Instructions[pos] = new StLoc(stloc_outer.Variable, new UserDefinedCompoundAssign(
920+
operatorCall.Method, CompoundEvalMode.EvaluatesToNewValue, target, targetKind, new LdcI4(1)));
921+
}
922+
return true;
923+
}
924+
847925
/// <code>
848926
/// stobj(target, binary.add(stloc l(ldobj(target)), ldc.i4 1))
849927
/// where target is pure and does not use 'l', and the 'stloc l' does not truncate

0 commit comments

Comments
 (0)