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. 72
      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 @@ -394,7 +394,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Adds two numbers.</summary>
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 @@ -407,7 +407,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Subtracts two numbers</summary>
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 @@ -420,7 +420,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Multiplies two numbers</summary>
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 @@ -433,7 +433,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Divides two numbers</summary>
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 @@ -450,7 +450,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Division remainder</summary>
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 @@ -467,7 +467,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise AND</summary>
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 @@ -480,7 +480,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise OR</summary>
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 @@ -493,7 +493,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise XOR</summary>
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 @@ -1127,7 +1127,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Shift left</summary>
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 @@ -1140,7 +1140,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Shift right</summary>
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 @@ -2277,29 +2277,29 @@ namespace ICSharpCode.Decompiler.IL
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) {
case OpCode.Add:
return new Add(left, right, checkForOverflow, sign);
return new Add(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.Sub:
return new Sub(left, right, checkForOverflow, sign);
return new Sub(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.Mul:
return new Mul(left, right, checkForOverflow, sign);
return new Mul(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.Div:
return new Div(left, right, checkForOverflow, sign);
return new Div(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.Rem:
return new Rem(left, right, checkForOverflow, sign);
return new Rem(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.BitAnd:
return new BitAnd(left, right, checkForOverflow, sign);
return new BitAnd(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.BitOr:
return new BitOr(left, right, checkForOverflow, sign);
return new BitOr(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.BitXor:
return new BitXor(left, right, checkForOverflow, sign);
return new BitXor(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.Shl:
return new Shl(left, right, checkForOverflow, sign);
return new Shl(left, right, checkForOverflow, sign, compoundAssignmentType);
case OpCode.Shr:
return new Shr(left, right, checkForOverflow, sign);
return new Shr(left, right, checkForOverflow, sign, compoundAssignmentType);
default:
throw new ArgumentException("opCode is not a binary numeric instruction");
}

10
ICSharpCode.Decompiler/IL/Instructions.tt

@ -185,8 +185,6 @@ @@ -185,8 +185,6 @@
new OpCode("ldelema", "Load address of array element.",
CustomClassName("LdElema"), CustomArguments("array", "index"), HasTypeOperand,
MayThrow, ResultType("Ref"), SupportsReadonlyPrefix),
};
#>
using System;
@ -254,12 +252,12 @@ namespace ICSharpCode.Decompiler.IL @@ -254,12 +252,12 @@ namespace ICSharpCode.Decompiler.IL
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) {
<# foreach (OpCode opCode in opCodes.Where(c => c.BaseClass == "BinaryNumericInstruction")) { #>
case OpCode.<#=opCode.Name#>:
return new <#=opCode.Name#>(left, right, checkForOverflow, sign);
return new <#=opCode.Name#>(left, right, checkForOverflow, sign, compoundAssignmentType);
<# } #>
default:
throw new ArgumentException("opCode is not a binary numeric instruction");
@ -485,10 +483,10 @@ namespace ICSharpCode.Decompiler.IL @@ -485,10 +483,10 @@ namespace ICSharpCode.Decompiler.IL
opCode.BaseClass = "BinaryNumericInstruction";
opCode.ConstructorParameters.Add("bool checkForOverflow");
opCode.BaseConstructorArguments.Add("checkForOverflow");
opCode.WriteOpCodeSuffix.Add("if (checkForOverflow) output.Write(\".ovf\");");
opCode.ConstructorParameters.Add("Sign 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.

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

@ -24,8 +24,20 @@ using System.Text; @@ -24,8 +24,20 @@ using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
public enum CompoundAssignmentType : byte
{
None,
EvaluatesToOldValue,
EvaluatesToNewValue
}
public abstract partial class BinaryNumericInstruction : BinaryInstruction
{
/// <summary>
/// Gets whether this instruction is a compound assignment.
/// </summary>
public readonly CompoundAssignmentType CompoundAssignmentType;
/// <summary>
/// Gets whether the instruction checks for overflow.
/// </summary>
@ -40,14 +52,32 @@ namespace ICSharpCode.Decompiler.IL @@ -40,14 +52,32 @@ namespace ICSharpCode.Decompiler.IL
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)
{
this.CheckForOverflow = checkForOverflow;
this.Sign = sign;
this.CompoundAssignmentType = compoundAssignmentType;
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)
{
// Based on Table 2: Binary Numeric Operations
@ -78,16 +108,54 @@ namespace ICSharpCode.Decompiler.IL @@ -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()
{
var flags = base.ComputeFlags();
if (CheckForOverflow)
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;
}
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);
if (CheckForOverflow)
output.Write(".ovf");

2
ICSharpCode.Decompiler/IL/NRTypeExtensions.cs

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

2
ICSharpCode.Decompiler/IL/StackType.cs

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

Loading…
Cancel
Save