Browse Source

[nullables] Lifted compound assignments

pull/897/head
Daniel Grunwald 8 years ago
parent
commit
61900e33c3
  1. 38
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 2
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  3. 24
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  4. 7
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  5. 19
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

38
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -743,18 +743,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -743,18 +743,9 @@ namespace ICSharpCode.Decompiler.CSharp
right = right.ConvertTo(compilation.FindType(KnownTypeCode.Int32), this);
}
TranslatedExpression result = new BinaryOperatorExpression(left.Expression, op, right.Expression)
return new BinaryOperatorExpression(left.Expression, op, right.Expression)
.WithILInstruction(inst)
.WithRR(resolver.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult));
if (inst.UnderlyingResultType == StackType.I) {
// C# doesn't have shift operators for IntPtr, so we first shifted a long/ulong,
// and now have to case back down to IntPtr/UIntPtr:
IType targetType = compilation.FindType(sign == Sign.Unsigned ? KnownTypeCode.UIntPtr : KnownTypeCode.IntPtr);
if (inst.IsLifted)
targetType = NullableType.Create(compilation, targetType);
result = result.ConvertTo(targetType, this);
}
return result;
}
protected internal override TranslatedExpression VisitCompoundAssignmentInstruction(CompoundAssignmentInstruction inst, TranslationContext context)
@ -789,7 +780,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -789,7 +780,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
var target = Translate(inst.Target);
var value = Translate(inst.Value);
value = PrepareArithmeticArgument(value, inst.Value.ResultType, inst.Sign, isLifted: false);
value = PrepareArithmeticArgument(value, inst.RightInputType, inst.Sign, inst.IsLifted);
TranslatedExpression resultExpr;
if (inst.CompoundAssignmentType == CompoundAssignmentType.EvaluatesToOldValue) {
@ -835,26 +826,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -835,26 +826,17 @@ namespace ICSharpCode.Decompiler.CSharp
{
var target = Translate(inst.Target);
var value = Translate(inst.Value);
IType targetType;
if (inst.ResultType == StackType.I4)
targetType = compilation.FindType(inst.Sign == Sign.Unsigned ? KnownTypeCode.UInt32 : KnownTypeCode.Int32);
else
targetType = compilation.FindType(inst.Sign == Sign.Unsigned ? KnownTypeCode.UInt64 : KnownTypeCode.Int64);
target = target.ConvertTo(targetType, this);
// Shift operators in C# always expect type 'int' on the right-hand-side
value = value.ConvertTo(compilation.FindType(KnownTypeCode.Int32), this);
TranslatedExpression result = new AssignmentExpression(target.Expression, op, value.Expression)
if (NullableType.IsNullable(value.Type)) {
value = value.ConvertTo(NullableType.Create(compilation, compilation.FindType(KnownTypeCode.Int32)), this);
} else {
value = value.ConvertTo(compilation.FindType(KnownTypeCode.Int32), this);
}
return new AssignmentExpression(target.Expression, op, value.Expression)
.WithILInstruction(inst)
.WithRR(resolver.ResolveAssignment(op, target.ResolveResult, value.ResolveResult));
if (inst.ResultType == StackType.I) {
// C# doesn't have shift operators for IntPtr, so we first shifted a long/ulong,
// and now have to case back down to IntPtr/UIntPtr:
result = result.ConvertTo(compilation.FindType(inst.Sign == Sign.Unsigned ? KnownTypeCode.UIntPtr : KnownTypeCode.IntPtr), this);
}
return result;
}
static bool AssignmentOperatorMightCheckForOverflow(AssignmentOperatorType op)

2
ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs

@ -60,7 +60,7 @@ namespace ICSharpCode.Decompiler.IL @@ -60,7 +60,7 @@ namespace ICSharpCode.Decompiler.IL
public readonly BinaryNumericOperator Operator;
/// <summary>
/// Gets whether this conversion is a lifted nullable operation.
/// Gets whether this is a lifted nullable operation.
/// </summary>
/// <remarks>
/// A lifted binary operation allows its arguments to be a value of type Nullable{T}, where

24
ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs

@ -41,7 +41,11 @@ namespace ICSharpCode.Decompiler.IL @@ -41,7 +41,11 @@ namespace ICSharpCode.Decompiler.IL
/// For instructions that produce the same result for either sign, returns Sign.None.
/// </summary>
public readonly Sign Sign;
public readonly StackType LeftInputType;
public readonly StackType RightInputType;
public StackType UnderlyingResultType { get; }
/// <summary>
/// The operator used by this assignment operator instruction.
/// </summary>
@ -49,17 +53,23 @@ namespace ICSharpCode.Decompiler.IL @@ -49,17 +53,23 @@ namespace ICSharpCode.Decompiler.IL
public readonly CompoundAssignmentType CompoundAssignmentType;
public CompoundAssignmentInstruction(BinaryNumericOperator op, ILInstruction target, ILInstruction value, IType type, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssigmentType)
public bool IsLifted { get; }
public CompoundAssignmentInstruction(BinaryNumericInstruction binary, ILInstruction target, ILInstruction value, IType type, CompoundAssignmentType compoundAssignmentType)
: base(OpCode.CompoundAssignmentInstruction)
{
this.CheckForOverflow = checkForOverflow;
this.Sign = sign;
this.Operator = op;
this.CheckForOverflow = binary.CheckForOverflow;
this.Sign = binary.Sign;
this.LeftInputType = binary.LeftInputType;
this.RightInputType = binary.RightInputType;
this.UnderlyingResultType = binary.UnderlyingResultType;
this.Operator = binary.Operator;
this.CompoundAssignmentType = compoundAssignmentType;
this.IsLifted = binary.IsLifted;
this.Target = target;
this.type = type;
this.Value = value;
this.CompoundAssignmentType = compoundAssigmentType;
Debug.Assert(compoundAssigmentType == CompoundAssignmentType.EvaluatesToNewValue || (op == BinaryNumericOperator.Add || op == BinaryNumericOperator.Sub));
Debug.Assert(compoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue || (Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub));
Debug.Assert(IsValidCompoundAssignmentTarget(Target));
}

7
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -283,7 +283,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -283,7 +283,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
}
// This transform is required because ILInlining only works with stloc/ldloc
protected internal override void VisitStObj(StObj inst)
{
base.VisitStObj(inst);
@ -292,17 +291,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -292,17 +291,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
if (inst.Value is BinaryNumericInstruction binary
&& !binary.IsLifted
&& binary.Left.MatchLdObj(out ILInstruction target, out IType t)
&& inst.Target.Match(target).Success)
{
context.Step("compound assignment", inst);
// stobj(target, binary.op(ldobj(target), ...))
// => compound.op(target, ...)
inst.ReplaceWith(new CompoundAssignmentInstruction(binary.Operator, binary.Left, binary.Right, t, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToNewValue));
inst.ReplaceWith(new CompoundAssignmentInstruction(
binary, binary.Left, binary.Right,
t, CompoundAssignmentType.EvaluatesToNewValue));
}
}
// This transform is required because ILInlining only works with stloc/ldloc
internal static bool StObjToStLoc(StObj inst, ILTransformContext context)
{
if (inst.Target.MatchLdLoca(out ILVariable v)

19
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -147,13 +147,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -147,13 +147,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var usages = next.Descendants.Where(d => d.MatchLdLoc(localVariable)).ToArray();
if (usages.Length != 1)
return false;
if (binary.IsLifted)
return false;
context.Step($"Compound assignment to '{owner.Name}'", setterCall);
block.Instructions.RemoveAt(i + 1);
block.Instructions.RemoveAt(i);
usages[0].ReplaceWith(new CompoundAssignmentInstruction(binary.Operator, getterCall, binary.Right,
getterCall.Method.ReturnType, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToNewValue));
usages[0].ReplaceWith(new CompoundAssignmentInstruction(
binary, getterCall, binary.Right,
getterCall.Method.ReturnType, CompoundAssignmentType.EvaluatesToNewValue));
return true;
}
@ -239,10 +238,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -239,10 +238,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (binary == null || !binary.Left.MatchLdLoc(nextInst.Variable) || !binary.Right.MatchLdcI4(1)
|| (binary.Operator != BinaryNumericOperator.Add && binary.Operator != BinaryNumericOperator.Sub))
return false;
if (binary.IsLifted)
return false;
context.Step($"TransformPostIncDecOperator", inst);
var assignment = new CompoundAssignmentInstruction(binary.Operator, new LdObj(inst.Value, targetType), binary.Right, targetType, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToOldValue);
var assignment = new CompoundAssignmentInstruction(binary, new LdObj(inst.Value, targetType), binary.Right, targetType, CompoundAssignmentType.EvaluatesToOldValue);
stobj.ReplaceWith(new StLoc(nextInst.Variable, assignment));
block.Instructions.RemoveAt(i + 1);
return true;
@ -291,10 +288,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -291,10 +288,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (binary == null || !binary.Left.MatchLdLoc(fieldValue.Variable) || !binary.Right.MatchLdcI4(1)
|| (binary.Operator != BinaryNumericOperator.Add && binary.Operator != BinaryNumericOperator.Sub))
return false;
if (binary.IsLifted)
return false;
context.Step($"TransformCSharp4PostIncDecOperatorOnAddress", baseFieldAddress);
var assignment = new CompoundAssignmentInstruction(binary.Operator, new LdObj(baseAddress, t), binary.Right, t, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToOldValue);
var assignment = new CompoundAssignmentInstruction(binary, new LdObj(baseAddress, t), binary.Right, t, CompoundAssignmentType.EvaluatesToOldValue);
stobj.ReplaceWith(new StLoc(fieldValueCopyToLocal.Variable, assignment));
block.Instructions.RemoveAt(i + 2);
block.Instructions.RemoveAt(i + 1);
@ -323,10 +318,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -323,10 +318,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var binary = stobj.Value as BinaryNumericInstruction;
if (binary == null || !binary.Left.MatchLdLoc(inst.Variable) || !binary.Right.MatchLdcI4(1))
return false;
if (binary.IsLifted)
return false;
context.Step($"TransformPostIncDecOnStaticField", inst);
var assignment = new CompoundAssignmentInstruction(binary.Operator, inst.Value, binary.Right, type, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToOldValue);
var assignment = new CompoundAssignmentInstruction(binary, inst.Value, binary.Right, type, CompoundAssignmentType.EvaluatesToOldValue);
stobj.ReplaceWith(new StLoc(inst.Variable, assignment));
return true;
}

Loading…
Cancel
Save