Browse Source

Add CompoundAssignment mode to BinaryNumericInstruction

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
ea0eaf9623
  1. 42
      ICSharpCode.Decompiler/IL/Instructions.cs
  2. 10
      ICSharpCode.Decompiler/IL/Instructions.tt
  3. 70
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  4. 2
      ICSharpCode.Decompiler/IL/NRTypeExtensions.cs
  5. 2
      ICSharpCode.Decompiler/IL/StackType.cs

42
ICSharpCode.Decompiler/IL/Instructions.cs

@ -394,7 +394,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Adds two numbers.</summary> /// <summary>Adds two numbers.</summary>
public sealed partial class Add : BinaryNumericInstruction public sealed partial class Add : BinaryNumericInstruction
{ {
public Add(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Add, left, right, checkForOverflow, sign) public Add(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None) : base(OpCode.Add, left, right, checkForOverflow, sign, compoundAssignmentType)
{ {
} }
@ -407,7 +407,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Subtracts two numbers</summary> /// <summary>Subtracts two numbers</summary>
public sealed partial class Sub : BinaryNumericInstruction public sealed partial class Sub : BinaryNumericInstruction
{ {
public Sub(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Sub, left, right, checkForOverflow, sign) public Sub(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None) : base(OpCode.Sub, left, right, checkForOverflow, sign, compoundAssignmentType)
{ {
} }
@ -420,7 +420,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Multiplies two numbers</summary> /// <summary>Multiplies two numbers</summary>
public sealed partial class Mul : BinaryNumericInstruction public sealed partial class Mul : BinaryNumericInstruction
{ {
public Mul(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Mul, left, right, checkForOverflow, sign) public Mul(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None) : base(OpCode.Mul, left, right, checkForOverflow, sign, compoundAssignmentType)
{ {
} }
@ -433,7 +433,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Divides two numbers</summary> /// <summary>Divides two numbers</summary>
public sealed partial class Div : BinaryNumericInstruction public sealed partial class Div : BinaryNumericInstruction
{ {
public Div(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Div, left, right, checkForOverflow, sign) public Div(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None) : base(OpCode.Div, left, right, checkForOverflow, sign, compoundAssignmentType)
{ {
} }
@ -450,7 +450,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Division remainder</summary> /// <summary>Division remainder</summary>
public sealed partial class Rem : BinaryNumericInstruction public sealed partial class Rem : BinaryNumericInstruction
{ {
public Rem(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Rem, left, right, checkForOverflow, sign) public Rem(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None) : base(OpCode.Rem, left, right, checkForOverflow, sign, compoundAssignmentType)
{ {
} }
@ -467,7 +467,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise AND</summary> /// <summary>Bitwise AND</summary>
public sealed partial class BitAnd : BinaryNumericInstruction public sealed partial class BitAnd : BinaryNumericInstruction
{ {
public BitAnd(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.BitAnd, left, right, checkForOverflow, sign) public BitAnd(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None) : base(OpCode.BitAnd, left, right, checkForOverflow, sign, compoundAssignmentType)
{ {
} }
@ -480,7 +480,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise OR</summary> /// <summary>Bitwise OR</summary>
public sealed partial class BitOr : BinaryNumericInstruction public sealed partial class BitOr : BinaryNumericInstruction
{ {
public BitOr(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.BitOr, left, right, checkForOverflow, sign) public BitOr(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None) : base(OpCode.BitOr, left, right, checkForOverflow, sign, compoundAssignmentType)
{ {
} }
@ -493,7 +493,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise XOR</summary> /// <summary>Bitwise XOR</summary>
public sealed partial class BitXor : BinaryNumericInstruction public sealed partial class BitXor : BinaryNumericInstruction
{ {
public BitXor(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.BitXor, left, right, checkForOverflow, sign) public BitXor(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None) : base(OpCode.BitXor, left, right, checkForOverflow, sign, compoundAssignmentType)
{ {
} }
@ -1127,7 +1127,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Shift left</summary> /// <summary>Shift left</summary>
public sealed partial class Shl : BinaryNumericInstruction public sealed partial class Shl : BinaryNumericInstruction
{ {
public Shl(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Shl, left, right, checkForOverflow, sign) public Shl(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None) : base(OpCode.Shl, left, right, checkForOverflow, sign, compoundAssignmentType)
{ {
} }
@ -1140,7 +1140,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Shift right</summary> /// <summary>Shift right</summary>
public sealed partial class Shr : BinaryNumericInstruction public sealed partial class Shr : BinaryNumericInstruction
{ {
public Shr(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Shr, left, right, checkForOverflow, sign) public Shr(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None) : base(OpCode.Shr, left, right, checkForOverflow, sign, compoundAssignmentType)
{ {
} }
@ -2277,29 +2277,29 @@ namespace ICSharpCode.Decompiler.IL
partial class BinaryNumericInstruction partial class BinaryNumericInstruction
{ {
public static BinaryNumericInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) public static BinaryNumericInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None)
{ {
switch (opCode) { switch (opCode) {
case OpCode.Add: case OpCode.Add:
return new Add(left, right, checkForOverflow, sign); return new Add(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.Sub: case OpCode.Sub:
return new Sub(left, right, checkForOverflow, sign); return new Sub(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.Mul: case OpCode.Mul:
return new Mul(left, right, checkForOverflow, sign); return new Mul(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.Div: case OpCode.Div:
return new Div(left, right, checkForOverflow, sign); return new Div(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.Rem: case OpCode.Rem:
return new Rem(left, right, checkForOverflow, sign); return new Rem(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.BitAnd: case OpCode.BitAnd:
return new BitAnd(left, right, checkForOverflow, sign); return new BitAnd(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.BitOr: case OpCode.BitOr:
return new BitOr(left, right, checkForOverflow, sign); return new BitOr(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.BitXor: case OpCode.BitXor:
return new BitXor(left, right, checkForOverflow, sign); return new BitXor(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.Shl: case OpCode.Shl:
return new Shl(left, right, checkForOverflow, sign); return new Shl(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.Shr: case OpCode.Shr:
return new Shr(left, right, checkForOverflow, sign); return new Shr(left, right, checkForOverflow, sign, compoundAssignmentType);
default: default:
throw new ArgumentException("opCode is not a binary numeric instruction"); throw new ArgumentException("opCode is not a binary numeric instruction");
} }

10
ICSharpCode.Decompiler/IL/Instructions.tt

@ -185,8 +185,6 @@
new OpCode("ldelema", "Load address of array element.", new OpCode("ldelema", "Load address of array element.",
CustomClassName("LdElema"), CustomArguments("array", "index"), HasTypeOperand, CustomClassName("LdElema"), CustomArguments("array", "index"), HasTypeOperand,
MayThrow, ResultType("Ref"), SupportsReadonlyPrefix), MayThrow, ResultType("Ref"), SupportsReadonlyPrefix),
}; };
#> #>
using System; using System;
@ -254,12 +252,12 @@ namespace ICSharpCode.Decompiler.IL
partial class BinaryNumericInstruction partial class BinaryNumericInstruction
{ {
public static BinaryNumericInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) public static BinaryNumericInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None)
{ {
switch (opCode) { switch (opCode) {
<# foreach (OpCode opCode in opCodes.Where(c => c.BaseClass == "BinaryNumericInstruction")) { #> <# foreach (OpCode opCode in opCodes.Where(c => c.BaseClass == "BinaryNumericInstruction")) { #>
case OpCode.<#=opCode.Name#>: case OpCode.<#=opCode.Name#>:
return new <#=opCode.Name#>(left, right, checkForOverflow, sign); return new <#=opCode.Name#>(left, right, checkForOverflow, sign, compoundAssignmentType);
<# } #> <# } #>
default: default:
throw new ArgumentException("opCode is not a binary numeric instruction"); throw new ArgumentException("opCode is not a binary numeric instruction");
@ -485,10 +483,10 @@ namespace ICSharpCode.Decompiler.IL
opCode.BaseClass = "BinaryNumericInstruction"; opCode.BaseClass = "BinaryNumericInstruction";
opCode.ConstructorParameters.Add("bool checkForOverflow"); opCode.ConstructorParameters.Add("bool checkForOverflow");
opCode.BaseConstructorArguments.Add("checkForOverflow"); opCode.BaseConstructorArguments.Add("checkForOverflow");
opCode.WriteOpCodeSuffix.Add("if (checkForOverflow) output.Write(\".ovf\");");
opCode.ConstructorParameters.Add("Sign sign"); opCode.ConstructorParameters.Add("Sign sign");
opCode.BaseConstructorArguments.Add("sign"); opCode.BaseConstructorArguments.Add("sign");
opCode.WriteOpCodeSuffix.Add("if (sign == Sign.Unsigned) output.Write(\".un\");"); opCode.ConstructorParameters.Add("CompoundAssignmentType compoundAssignmentType = CompoundAssignmentType.None");
opCode.BaseConstructorArguments.Add("compoundAssignmentType");
}; };
// BinaryNumeric trait: the instruction is derived from BinaryComparisonInstruction. Implies Binary and I4Result. // BinaryNumeric trait: the instruction is derived from BinaryComparisonInstruction. Implies Binary and I4Result.

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

@ -24,8 +24,20 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
public enum CompoundAssignmentType : byte
{
None,
EvaluatesToOldValue,
EvaluatesToNewValue
}
public abstract partial class BinaryNumericInstruction : BinaryInstruction public abstract partial class BinaryNumericInstruction : BinaryInstruction
{ {
/// <summary>
/// Gets whether this instruction is a compound assignment.
/// </summary>
public readonly CompoundAssignmentType CompoundAssignmentType;
/// <summary> /// <summary>
/// Gets whether the instruction checks for overflow. /// Gets whether the instruction checks for overflow.
/// </summary> /// </summary>
@ -40,12 +52,30 @@ namespace ICSharpCode.Decompiler.IL
readonly StackType resultType; readonly StackType resultType;
protected BinaryNumericInstruction(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) protected BinaryNumericInstruction(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign, CompoundAssignmentType compoundAssignmentType)
: base(opCode, left, right) : base(opCode, left, right)
{ {
this.CheckForOverflow = checkForOverflow; this.CheckForOverflow = checkForOverflow;
this.Sign = sign; this.Sign = sign;
this.CompoundAssignmentType = compoundAssignmentType;
this.resultType = ComputeResultType(opCode, left.ResultType, right.ResultType); this.resultType = ComputeResultType(opCode, left.ResultType, right.ResultType);
Debug.Assert(CompoundAssignmentType == CompoundAssignmentType.None || IsValidCompoundAssignmentTarget(Left));
}
internal static bool IsValidCompoundAssignmentTarget(ILInstruction inst)
{
switch (inst.OpCode) {
case OpCode.LdLoc:
case OpCode.LdFld:
case OpCode.LdsFld:
case OpCode.LdObj:
return true;
case OpCode.Call:
case OpCode.CallVirt:
return true; // TODO: check if corresponding setter exists
default:
return false;
}
} }
internal static StackType ComputeResultType(OpCode opCode, StackType left, StackType right) internal static StackType ComputeResultType(OpCode opCode, StackType left, StackType right)
@ -78,16 +108,54 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
internal override void CheckInvariant()
{
base.CheckInvariant();
Debug.Assert(CompoundAssignmentType == CompoundAssignmentType.None || IsValidCompoundAssignmentTarget(Left));
}
protected override void Connected()
{
base.Connected();
// Count the local variable store due to the compound assignment:
ILVariable v;
if (CompoundAssignmentType != CompoundAssignmentType.None && Left.MatchLdLoc(out v)) {
v.StoreCount++;
}
}
protected override void Disconnected()
{
base.Disconnected();
// Count the local variable store due to the compound assignment:
ILVariable v;
if (CompoundAssignmentType != CompoundAssignmentType.None && Left.MatchLdLoc(out v)) {
v.StoreCount--;
}
}
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
var flags = base.ComputeFlags(); var flags = base.ComputeFlags();
if (CheckForOverflow) if (CheckForOverflow)
flags |= InstructionFlags.MayThrow; flags |= InstructionFlags.MayThrow;
// Set MayWriteLocals if this is a compound assignment to a local variable
if (CompoundAssignmentType != CompoundAssignmentType.None && Left.OpCode == OpCode.LdLoc)
flags |= InstructionFlags.MayWriteLocals;
return flags; return flags;
} }
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
switch (CompoundAssignmentType) {
case CompoundAssignmentType.EvaluatesToNewValue:
output.Write("compound.assign");
break;
case CompoundAssignmentType.EvaluatesToOldValue:
output.Write("compound.assign.oldvalue");
break;
}
output.Write(OpCode); output.Write(OpCode);
if (CheckForOverflow) if (CheckForOverflow)
output.Write(".ovf"); output.Write(".ovf");

2
ICSharpCode.Decompiler/IL/NRTypeExtensions.cs

@ -148,7 +148,7 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
public enum Sign public enum Sign : byte
{ {
None, None,
Signed, Signed,

2
ICSharpCode.Decompiler/IL/StackType.cs

@ -27,7 +27,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// A type for the purpose of stack analysis. /// A type for the purpose of stack analysis.
/// </summary> /// </summary>
public enum StackType public enum StackType : byte
{ {
Unknown, Unknown,
/// <summary>32-bit integer</summary> /// <summary>32-bit integer</summary>

Loading…
Cancel
Save