Skip to content

Commit f4d746e

Browse files
Merge pull request #3472 from ds5678/preincrement-attempt
Preincrement improvements
2 parents 0c2b001 + f860777 commit f4d746e

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4946,5 +4946,23 @@ public void Issue1779(int value)
49464946
CustomStruct2 customStruct = GetStruct();
49474947
customStruct.IntProp += value;
49484948
}
4949+
4950+
#if ROSLYN2
4951+
public static string PreIncrementWithMethodCall(int value)
4952+
{
4953+
return (++value).ToString();
4954+
}
4955+
#endif
4956+
4957+
#if CS72
4958+
public static string PreIncrementWithInParameter(int value)
4959+
{
4960+
PreIncrementWithInParameter_Helper(++value);
4961+
return value.ToString();
4962+
}
4963+
public static void PreIncrementWithInParameter_Helper(in int value)
4964+
{
4965+
}
4966+
#endif
49494967
}
49504968
}

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)