Browse Source

Merge binary arithmetic instructions into one class.

pull/734/head
Siegfried Pammer 9 years ago
parent
commit
3a89500e0c
  1. 58
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 2
      ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs
  3. 52
      ICSharpCode.Decompiler/IL/ILReader.cs
  4. 442
      ICSharpCode.Decompiler/IL/Instructions.cs
  5. 37
      ICSharpCode.Decompiler/IL/Instructions.tt
  6. 75
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  7. 19
      ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs
  8. 2
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

58
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -474,44 +474,32 @@ namespace ICSharpCode.Decompiler.CSharp @@ -474,44 +474,32 @@ namespace ICSharpCode.Decompiler.CSharp
.WithRR(new OperatorResolveResult(left.Type, ExpressionType.Assign, left.ResolveResult, right.ResolveResult));
}
protected internal override TranslatedExpression VisitAdd(Add inst)
protected internal override TranslatedExpression VisitBinaryNumericInstruction(BinaryNumericInstruction inst)
{
switch (inst.Operator) {
case BinaryNumericOperator.Add:
return HandleBinaryNumeric(inst, BinaryOperatorType.Add);
}
protected internal override TranslatedExpression VisitSub(Sub inst)
{
case BinaryNumericOperator.Sub:
return HandleBinaryNumeric(inst, BinaryOperatorType.Subtract);
}
protected internal override TranslatedExpression VisitMul(Mul inst)
{
case BinaryNumericOperator.Mul:
return HandleBinaryNumeric(inst, BinaryOperatorType.Multiply);
}
protected internal override TranslatedExpression VisitDiv(Div inst)
{
case BinaryNumericOperator.Div:
return HandleBinaryNumeric(inst, BinaryOperatorType.Divide);
}
protected internal override TranslatedExpression VisitRem(Rem inst)
{
case BinaryNumericOperator.Rem:
return HandleBinaryNumeric(inst, BinaryOperatorType.Modulus);
}
protected internal override TranslatedExpression VisitBitXor(BitXor inst)
{
return HandleBinaryNumeric(inst, BinaryOperatorType.ExclusiveOr);
}
protected internal override TranslatedExpression VisitBitAnd(BitAnd inst)
{
case BinaryNumericOperator.BitAnd:
return HandleBinaryNumeric(inst, BinaryOperatorType.BitwiseAnd);
}
protected internal override TranslatedExpression VisitBitOr(BitOr inst)
{
case BinaryNumericOperator.BitOr:
return HandleBinaryNumeric(inst, BinaryOperatorType.BitwiseOr);
case BinaryNumericOperator.BitXor:
return HandleBinaryNumeric(inst, BinaryOperatorType.ExclusiveOr);
case BinaryNumericOperator.ShiftLeft:
return HandleShift(inst, BinaryOperatorType.ShiftLeft);
case BinaryNumericOperator.ShiftRight:
return HandleShift(inst, BinaryOperatorType.ShiftRight);
default:
throw new ArgumentOutOfRangeException();
}
}
TranslatedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOperatorType op)
@ -583,16 +571,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -583,16 +571,6 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
protected internal override TranslatedExpression VisitShl(Shl inst)
{
return HandleShift(inst, BinaryOperatorType.ShiftLeft);
}
protected internal override TranslatedExpression VisitShr(Shr inst)
{
return HandleShift(inst, BinaryOperatorType.ShiftRight);
}
TranslatedExpression HandleShift(BinaryNumericInstruction inst, BinaryOperatorType op)
{
var left = Translate(inst.Left);

2
ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs

@ -436,7 +436,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -436,7 +436,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
ILInstruction left, right, value;
return block.Instructions.Count == 2
&& block.Instructions[0].MatchStLoc(nativeVar, out value)
&& value.MatchAdd(out left, out right)
&& value.MatchBinaryNumericInstruction(BinaryNumericOperator.Add, out left, out right)
&& left.MatchLdLoc(nativeVar)
&& IsOffsetToStringDataCall(right)
&& block.Instructions[1].MatchBranch(targetBlock);

52
ICSharpCode.Decompiler/IL/ILReader.cs

@ -335,13 +335,13 @@ namespace ICSharpCode.Decompiler.IL @@ -335,13 +335,13 @@ namespace ICSharpCode.Decompiler.IL
{
switch (PeekStackType()) {
case StackType.I4:
return Push(new Sub(new LdcI4(0), Pop(), checkForOverflow: false, sign: Sign.None));
return Push(new BinaryNumericInstruction(BinaryNumericOperator.Sub, new LdcI4(0), Pop(), checkForOverflow: false, sign: Sign.None));
case StackType.I:
return Push(new Sub(new Conv(new LdcI4(0), PrimitiveType.I, false, Sign.None), Pop(), checkForOverflow: false, sign: Sign.None));
return Push(new BinaryNumericInstruction(BinaryNumericOperator.Sub, new Conv(new LdcI4(0), PrimitiveType.I, false, Sign.None), Pop(), checkForOverflow: false, sign: Sign.None));
case StackType.I8:
return Push(new Sub(new LdcI8(0), Pop(), checkForOverflow: false, sign: Sign.None));
return Push(new BinaryNumericInstruction(BinaryNumericOperator.Sub, new LdcI8(0), Pop(), checkForOverflow: false, sign: Sign.None));
case StackType.F:
return Push(new Sub(new LdcF(0), Pop(), checkForOverflow: false, sign: Sign.None));
return Push(new BinaryNumericInstruction(BinaryNumericOperator.Sub, new LdcF(0), Pop(), checkForOverflow: false, sign: Sign.None));
default:
Warn("Unsupported input type for neg.");
goto case StackType.I4;
@ -363,13 +363,13 @@ namespace ICSharpCode.Decompiler.IL @@ -363,13 +363,13 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Volatile:
return DecodeVolatile();
case ILOpCode.Add:
return BinaryNumeric(OpCode.Add);
return BinaryNumeric(BinaryNumericOperator.Add);
case ILOpCode.Add_Ovf:
return BinaryNumeric(OpCode.Add, true, Sign.Signed);
return BinaryNumeric(BinaryNumericOperator.Add, true, Sign.Signed);
case ILOpCode.Add_Ovf_Un:
return BinaryNumeric(OpCode.Add, true, Sign.Unsigned);
return BinaryNumeric(BinaryNumericOperator.Add, true, Sign.Unsigned);
case ILOpCode.And:
return BinaryNumeric(OpCode.BitAnd);
return BinaryNumeric(BinaryNumericOperator.BitAnd);
case ILOpCode.Arglist:
return Push(new Arglist());
case ILOpCode.Beq:
@ -513,9 +513,9 @@ namespace ICSharpCode.Decompiler.IL @@ -513,9 +513,9 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Cpblk:
throw new NotImplementedException();
case ILOpCode.Div:
return BinaryNumeric(OpCode.Div, false, Sign.Signed);
return BinaryNumeric(BinaryNumericOperator.Div, false, Sign.Signed);
case ILOpCode.Div_Un:
return BinaryNumeric(OpCode.Div, false, Sign.Unsigned);
return BinaryNumeric(BinaryNumericOperator.Div, false, Sign.Unsigned);
case ILOpCode.Dup:
return Push(Peek());
case ILOpCode.Endfilter:
@ -607,11 +607,11 @@ namespace ICSharpCode.Decompiler.IL @@ -607,11 +607,11 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Localloc:
return Push(new LocAlloc(Pop()));
case ILOpCode.Mul:
return BinaryNumeric(OpCode.Mul, false, Sign.None);
return BinaryNumeric(BinaryNumericOperator.Mul, false, Sign.None);
case ILOpCode.Mul_Ovf:
return BinaryNumeric(OpCode.Mul, true, Sign.Signed);
return BinaryNumeric(BinaryNumericOperator.Mul, true, Sign.Signed);
case ILOpCode.Mul_Ovf_Un:
return BinaryNumeric(OpCode.Mul, true, Sign.Unsigned);
return BinaryNumeric(BinaryNumericOperator.Mul, true, Sign.Unsigned);
case ILOpCode.Neg:
return Neg();
case ILOpCode.Newobj:
@ -621,22 +621,22 @@ namespace ICSharpCode.Decompiler.IL @@ -621,22 +621,22 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Not:
return Push(new BitNot(Pop()));
case ILOpCode.Or:
return BinaryNumeric(OpCode.BitOr);
return BinaryNumeric(BinaryNumericOperator.BitOr);
case ILOpCode.Pop:
Pop();
return new Nop();
case ILOpCode.Rem:
return BinaryNumeric(OpCode.Rem, false, Sign.Signed);
return BinaryNumeric(BinaryNumericOperator.Rem, false, Sign.Signed);
case ILOpCode.Rem_Un:
return BinaryNumeric(OpCode.Rem, false, Sign.Unsigned);
return BinaryNumeric(BinaryNumericOperator.Rem, false, Sign.Unsigned);
case ILOpCode.Ret:
return Return();
case ILOpCode.Shl:
return BinaryNumeric(OpCode.Shl, false, Sign.None);
return BinaryNumeric(BinaryNumericOperator.ShiftLeft, false, Sign.None);
case ILOpCode.Shr:
return BinaryNumeric(OpCode.Shr, false, Sign.Signed);
return BinaryNumeric(BinaryNumericOperator.ShiftRight, false, Sign.Signed);
case ILOpCode.Shr_Un:
return BinaryNumeric(OpCode.Shr, false, Sign.Unsigned);
return BinaryNumeric(BinaryNumericOperator.ShiftRight, false, Sign.Unsigned);
case ILOpCode.Starg:
return Starg(reader.ReadUInt16());
case ILOpCode.Starg_S:
@ -667,15 +667,15 @@ namespace ICSharpCode.Decompiler.IL @@ -667,15 +667,15 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Stloc_3:
return Stloc(ilOpCode - ILOpCode.Stloc_0);
case ILOpCode.Sub:
return BinaryNumeric(OpCode.Sub, false, Sign.None);
return BinaryNumeric(BinaryNumericOperator.Sub, false, Sign.None);
case ILOpCode.Sub_Ovf:
return BinaryNumeric(OpCode.Sub, true, Sign.Signed);
return BinaryNumeric(BinaryNumericOperator.Sub, true, Sign.Signed);
case ILOpCode.Sub_Ovf_Un:
return BinaryNumeric(OpCode.Sub, true, Sign.Unsigned);
return BinaryNumeric(BinaryNumericOperator.Sub, true, Sign.Unsigned);
case ILOpCode.Switch:
return DecodeSwitch();
case ILOpCode.Xor:
return BinaryNumeric(OpCode.BitXor);
return BinaryNumeric(BinaryNumericOperator.BitXor);
case ILOpCode.Box:
{
var type = ReadAndDecodeTypeReference();
@ -1200,11 +1200,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1200,11 +1200,11 @@ namespace ICSharpCode.Decompiler.IL
return instr;
}
ILInstruction BinaryNumeric(OpCode opCode, bool checkForOverflow = false, Sign sign = Sign.None)
ILInstruction BinaryNumeric(BinaryNumericOperator @operator, bool checkForOverflow = false, Sign sign = Sign.None)
{
var right = Pop();
var left = Pop();
if (opCode != OpCode.Shl && opCode != OpCode.Shr) {
if (@operator != BinaryNumericOperator.ShiftLeft && @operator != BinaryNumericOperator.ShiftRight) {
// make the implicit I4->I conversion explicit:
if (left.ResultType == StackType.I4 && right.ResultType == StackType.I) {
left = new Conv(left, PrimitiveType.I, false, Sign.None);
@ -1212,7 +1212,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1212,7 +1212,7 @@ namespace ICSharpCode.Decompiler.IL
right = new Conv(right, PrimitiveType.I, false, Sign.None);
}
}
return Push(BinaryNumericInstruction.Create(opCode, left, right, checkForOverflow, sign));
return Push(new BinaryNumericInstruction(@operator, left, right, checkForOverflow, sign));
}
ILInstruction LdToken(IMetadataTokenProvider token)

442
ICSharpCode.Decompiler/IL/Instructions.cs

@ -43,22 +43,8 @@ namespace ICSharpCode.Decompiler.IL @@ -43,22 +43,8 @@ namespace ICSharpCode.Decompiler.IL
PinnedRegion,
/// <summary>Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).</summary>
LogicNot,
/// <summary>Adds two numbers.</summary>
Add,
/// <summary>Subtracts two numbers</summary>
Sub,
/// <summary>Multiplies two numbers</summary>
Mul,
/// <summary>Divides two numbers</summary>
Div,
/// <summary>Division remainder</summary>
Rem,
/// <summary>Bitwise AND</summary>
BitAnd,
/// <summary>Bitwise OR</summary>
BitOr,
/// <summary>Bitwise XOR</summary>
BitXor,
/// <summary>Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.</summary>
BinaryNumericInstruction,
/// <summary>Bitwise NOT</summary>
BitNot,
/// <summary>Retrieves the RuntimeArgumentHandle.</summary>
@ -125,10 +111,6 @@ namespace ICSharpCode.Decompiler.IL @@ -125,10 +111,6 @@ namespace ICSharpCode.Decompiler.IL
LocAlloc,
/// <summary>Returns from the current method or lambda.</summary>
Return,
/// <summary>Shift left</summary>
Shl,
/// <summary>Shift right</summary>
Shr,
/// <summary>Load address of instance field</summary>
LdFlda,
/// <summary>Load static field address</summary>
@ -722,157 +704,17 @@ namespace ICSharpCode.Decompiler.IL @@ -722,157 +704,17 @@ namespace ICSharpCode.Decompiler.IL
}
}
/// <summary>Adds two numbers.</summary>
public sealed partial class Add : BinaryNumericInstruction
/// <summary>Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.</summary>
public sealed partial class BinaryNumericInstruction : BinaryInstruction
{
public Add(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Add, left, right, checkForOverflow, sign)
{
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitAdd(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitAdd(this);
}
}
/// <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 override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitSub(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitSub(this);
}
}
/// <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 override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitMul(this);
visitor.VisitBinaryNumericInstruction(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitMul(this);
}
}
/// <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)
{
}
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return base.DirectFlags | InstructionFlags.MayThrow;
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitDiv(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitDiv(this);
}
}
/// <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)
{
}
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return base.DirectFlags | InstructionFlags.MayThrow;
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitRem(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitRem(this);
}
}
/// <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 override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitBitAnd(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitBitAnd(this);
}
}
/// <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 override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitBitOr(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitBitOr(this);
}
}
/// <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 override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitBitXor(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitBitXor(this);
return visitor.VisitBinaryNumericInstruction(this);
}
}
@ -1985,40 +1827,6 @@ namespace ICSharpCode.Decompiler.IL @@ -1985,40 +1827,6 @@ 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 override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitShl(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitShl(this);
}
}
/// <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 override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitShr(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitShr(this);
}
}
/// <summary>Load address of instance field</summary>
public sealed partial class LdFlda : ILInstruction, IInstructionWithFieldOperand
{
@ -3110,35 +2918,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3110,35 +2918,7 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitAdd(Add inst)
{
Default(inst);
}
protected internal virtual void VisitSub(Sub inst)
{
Default(inst);
}
protected internal virtual void VisitMul(Mul inst)
{
Default(inst);
}
protected internal virtual void VisitDiv(Div inst)
{
Default(inst);
}
protected internal virtual void VisitRem(Rem inst)
{
Default(inst);
}
protected internal virtual void VisitBitAnd(BitAnd inst)
{
Default(inst);
}
protected internal virtual void VisitBitOr(BitOr inst)
{
Default(inst);
}
protected internal virtual void VisitBitXor(BitXor inst)
protected internal virtual void VisitBinaryNumericInstruction(BinaryNumericInstruction inst)
{
Default(inst);
}
@ -3274,14 +3054,6 @@ namespace ICSharpCode.Decompiler.IL @@ -3274,14 +3054,6 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitShl(Shl inst)
{
Default(inst);
}
protected internal virtual void VisitShr(Shr inst)
{
Default(inst);
}
protected internal virtual void VisitLdFlda(LdFlda inst)
{
Default(inst);
@ -3404,35 +3176,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3404,35 +3176,7 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitAdd(Add inst)
{
return Default(inst);
}
protected internal virtual T VisitSub(Sub inst)
{
return Default(inst);
}
protected internal virtual T VisitMul(Mul inst)
{
return Default(inst);
}
protected internal virtual T VisitDiv(Div inst)
{
return Default(inst);
}
protected internal virtual T VisitRem(Rem inst)
{
return Default(inst);
}
protected internal virtual T VisitBitAnd(BitAnd inst)
{
return Default(inst);
}
protected internal virtual T VisitBitOr(BitOr inst)
{
return Default(inst);
}
protected internal virtual T VisitBitXor(BitXor inst)
protected internal virtual T VisitBinaryNumericInstruction(BinaryNumericInstruction inst)
{
return Default(inst);
}
@ -3568,14 +3312,6 @@ namespace ICSharpCode.Decompiler.IL @@ -3568,14 +3312,6 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitShl(Shl inst)
{
return Default(inst);
}
protected internal virtual T VisitShr(Shr inst)
{
return Default(inst);
}
protected internal virtual T VisitLdFlda(LdFlda inst)
{
return Default(inst);
@ -3662,37 +3398,6 @@ namespace ICSharpCode.Decompiler.IL @@ -3662,37 +3398,6 @@ namespace ICSharpCode.Decompiler.IL
}
}
partial class BinaryNumericInstruction
{
public static BinaryNumericInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign)
{
switch (opCode) {
case OpCode.Add:
return new Add(left, right, checkForOverflow, sign);
case OpCode.Sub:
return new Sub(left, right, checkForOverflow, sign);
case OpCode.Mul:
return new Mul(left, right, checkForOverflow, sign);
case OpCode.Div:
return new Div(left, right, checkForOverflow, sign);
case OpCode.Rem:
return new Rem(left, right, checkForOverflow, sign);
case OpCode.BitAnd:
return new BitAnd(left, right, checkForOverflow, sign);
case OpCode.BitOr:
return new BitOr(left, right, checkForOverflow, sign);
case OpCode.BitXor:
return new BitXor(left, right, checkForOverflow, sign);
case OpCode.Shl:
return new Shl(left, right, checkForOverflow, sign);
case OpCode.Shr:
return new Shr(left, right, checkForOverflow, sign);
default:
throw new ArgumentException("opCode is not a binary numeric instruction");
}
}
}
partial class BinaryComparisonInstruction
{
public static BinaryComparisonInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right)
@ -3714,14 +3419,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3714,14 +3419,7 @@ namespace ICSharpCode.Decompiler.IL
"Block",
"PinnedRegion",
"logic.not",
"add",
"sub",
"mul",
"div",
"rem",
"bit.and",
"bit.or",
"bit.xor",
"binary",
"bit.not",
"arglist",
"br",
@ -3755,8 +3453,6 @@ namespace ICSharpCode.Decompiler.IL @@ -3755,8 +3453,6 @@ namespace ICSharpCode.Decompiler.IL
"ldmembertoken",
"localloc",
"ret",
"shl",
"shr",
"ldflda",
"ldsflda",
"castclass",
@ -3823,102 +3519,6 @@ namespace ICSharpCode.Decompiler.IL @@ -3823,102 +3519,6 @@ namespace ICSharpCode.Decompiler.IL
argument = default(ILInstruction);
return false;
}
public bool MatchAdd(out ILInstruction left, out ILInstruction right)
{
var inst = this as Add;
if (inst != null) {
left = inst.Left;
right = inst.Right;
return true;
}
left = default(ILInstruction);
right = default(ILInstruction);
return false;
}
public bool MatchSub(out ILInstruction left, out ILInstruction right)
{
var inst = this as Sub;
if (inst != null) {
left = inst.Left;
right = inst.Right;
return true;
}
left = default(ILInstruction);
right = default(ILInstruction);
return false;
}
public bool MatchMul(out ILInstruction left, out ILInstruction right)
{
var inst = this as Mul;
if (inst != null) {
left = inst.Left;
right = inst.Right;
return true;
}
left = default(ILInstruction);
right = default(ILInstruction);
return false;
}
public bool MatchDiv(out ILInstruction left, out ILInstruction right)
{
var inst = this as Div;
if (inst != null) {
left = inst.Left;
right = inst.Right;
return true;
}
left = default(ILInstruction);
right = default(ILInstruction);
return false;
}
public bool MatchRem(out ILInstruction left, out ILInstruction right)
{
var inst = this as Rem;
if (inst != null) {
left = inst.Left;
right = inst.Right;
return true;
}
left = default(ILInstruction);
right = default(ILInstruction);
return false;
}
public bool MatchBitAnd(out ILInstruction left, out ILInstruction right)
{
var inst = this as BitAnd;
if (inst != null) {
left = inst.Left;
right = inst.Right;
return true;
}
left = default(ILInstruction);
right = default(ILInstruction);
return false;
}
public bool MatchBitOr(out ILInstruction left, out ILInstruction right)
{
var inst = this as BitOr;
if (inst != null) {
left = inst.Left;
right = inst.Right;
return true;
}
left = default(ILInstruction);
right = default(ILInstruction);
return false;
}
public bool MatchBitXor(out ILInstruction left, out ILInstruction right)
{
var inst = this as BitXor;
if (inst != null) {
left = inst.Left;
right = inst.Right;
return true;
}
left = default(ILInstruction);
right = default(ILInstruction);
return false;
}
public bool MatchBitNot(out ILInstruction argument)
{
var inst = this as BitNot;
@ -4121,30 +3721,6 @@ namespace ICSharpCode.Decompiler.IL @@ -4121,30 +3721,6 @@ namespace ICSharpCode.Decompiler.IL
argument = default(ILInstruction);
return false;
}
public bool MatchShl(out ILInstruction left, out ILInstruction right)
{
var inst = this as Shl;
if (inst != null) {
left = inst.Left;
right = inst.Right;
return true;
}
left = default(ILInstruction);
right = default(ILInstruction);
return false;
}
public bool MatchShr(out ILInstruction left, out ILInstruction right)
{
var inst = this as Shr;
if (inst != null) {
left = inst.Left;
right = inst.Right;
return true;
}
left = default(ILInstruction);
right = default(ILInstruction);
return false;
}
public bool MatchLdFlda(out ILInstruction target, out IField field)
{
var inst = this as LdFlda;

37
ICSharpCode.Decompiler/IL/Instructions.tt

@ -58,14 +58,8 @@ @@ -58,14 +58,8 @@
})),
new OpCode("logic.not", "Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).",
ResultType("I4"), Unary),
new OpCode("add", "Adds two numbers.", BinaryNumeric),
new OpCode("sub", "Subtracts two numbers", BinaryNumeric),
new OpCode("mul", "Multiplies two numbers", BinaryNumeric),
new OpCode("div", "Divides two numbers", BinaryNumeric, MayThrow),
new OpCode("rem", "Division remainder", BinaryNumeric, MayThrow),
new OpCode("bit.and", "Bitwise AND", BinaryNumeric),
new OpCode("bit.or", "Bitwise OR", BinaryNumeric),
new OpCode("bit.xor", "Bitwise XOR", BinaryNumeric),
new OpCode("binary", "Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.",
CustomClassName("BinaryNumericInstruction"), Binary, CustomWriteTo, CustomConstructor, CustomComputeFlags),
new OpCode("bit.not", "Bitwise NOT", Unary),
new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
new OpCode("br", "Unconditional branch. <c>goto target;</c>",
@ -143,8 +137,6 @@ @@ -143,8 +137,6 @@
CustomClassName("LocAlloc"), Unary, ResultType("I"), MayThrow),
new OpCode("ret", "Returns from the current method or lambda.",
CustomClassName("Return"), CustomConstructor, CustomComputeFlags, MayBranch, UnconditionalBranch),
new OpCode("shl", "Shift left", BinaryNumeric),
new OpCode("shr", "Shift right", BinaryNumeric),
new OpCode("ldflda", "Load address of instance field",
CustomClassName("LdFlda"), CustomArguments("target"), MayThrowIfNotDelayed, HasFieldOperand, ResultType("Ref")),
@ -289,21 +281,6 @@ namespace ICSharpCode.Decompiler.IL @@ -289,21 +281,6 @@ namespace ICSharpCode.Decompiler.IL
<# } #>
}
partial class BinaryNumericInstruction
{
public static BinaryNumericInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign)
{
switch (opCode) {
<# foreach (OpCode opCode in opCodes.Where(c => c.BaseClass == "BinaryNumericInstruction")) { #>
case OpCode.<#=opCode.Name#>:
return new <#=opCode.Name#>(left, right, checkForOverflow, sign);
<# } #>
default:
throw new ArgumentException("opCode is not a binary numeric instruction");
}
}
}
partial class BinaryComparisonInstruction
{
public static BinaryComparisonInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right)
@ -565,16 +542,6 @@ namespace ICSharpCode.Decompiler.IL @@ -565,16 +542,6 @@ namespace ICSharpCode.Decompiler.IL
opCode.WriteArguments.Add("output.Write(')');");
};
// BinaryNumeric trait: the instruction is derived from BinaryNumericInstruction. Implies Binary; and implies MayThrow if the overflow mode is checked.
static Action<OpCode> BinaryNumeric = opCode => {
Binary(opCode);
opCode.BaseClass = "BinaryNumericInstruction";
opCode.ConstructorParameters.Add("bool checkForOverflow");
opCode.BaseConstructorArguments.Add("checkForOverflow");
opCode.ConstructorParameters.Add("Sign sign");
opCode.BaseConstructorArguments.Add("sign");
};
static Action<OpCode> CustomArguments(params string[] arguments)
{
return CustomChildren(arguments.Select(arg => new ArgumentInfo(arg)).ToArray(), generateInline: true);

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

@ -31,7 +31,21 @@ namespace ICSharpCode.Decompiler.IL @@ -31,7 +31,21 @@ namespace ICSharpCode.Decompiler.IL
EvaluatesToNewValue
}
public abstract partial class BinaryNumericInstruction : BinaryInstruction
public enum BinaryNumericOperator : byte
{
Add,
Sub,
Mul,
Div,
Rem,
BitAnd,
BitOr,
BitXor,
ShiftLeft,
ShiftRight
}
public partial class BinaryNumericInstruction : BinaryInstruction
{
/// <summary>
/// Gets whether the instruction checks for overflow.
@ -45,14 +59,20 @@ namespace ICSharpCode.Decompiler.IL @@ -45,14 +59,20 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public readonly Sign Sign;
/// <summary>
/// The operator used by this binary operator instruction.
/// </summary>
public readonly BinaryNumericOperator Operator;
readonly StackType resultType;
protected BinaryNumericInstruction(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign)
: base(opCode, left, right)
public BinaryNumericInstruction(BinaryNumericOperator op, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign)
: base(OpCode.BinaryNumericInstruction, left, right)
{
this.CheckForOverflow = checkForOverflow;
this.Sign = sign;
this.resultType = ComputeResultType(opCode, left.ResultType, right.ResultType);
this.Operator = op;
this.resultType = ComputeResultType(op, left.ResultType, right.ResultType);
Debug.Assert(resultType != StackType.Unknown);
//Debug.Assert(CompoundAssignmentType == CompoundAssignmentType.None || IsValidCompoundAssignmentTarget(Left));
}
@ -71,23 +91,23 @@ namespace ICSharpCode.Decompiler.IL @@ -71,23 +91,23 @@ namespace ICSharpCode.Decompiler.IL
}
}
internal static StackType ComputeResultType(OpCode opCode, StackType left, StackType right)
internal static StackType ComputeResultType(BinaryNumericOperator op, StackType left, StackType right)
{
// Based on Table 2: Binary Numeric Operations
// also works for Table 5: Integer Operations
// and for Table 7: Overflow Arithmetic Operations
if (left == right || opCode == OpCode.Shl || opCode == OpCode.Shr) {
if (left == right || op == BinaryNumericOperator.ShiftLeft || op == BinaryNumericOperator.ShiftRight) {
// Shift op codes use Table 6
return left;
}
if (left == StackType.Ref || right == StackType.Ref) {
if (left == StackType.Ref && right == StackType.Ref) {
// sub(&, &) = I
Debug.Assert(opCode == OpCode.Sub);
Debug.Assert(op == BinaryNumericOperator.Sub);
return StackType.I;
} else {
// add/sub with I or I4 and &
Debug.Assert(opCode == OpCode.Add || opCode == OpCode.Sub);
Debug.Assert(op == BinaryNumericOperator.Add || op == BinaryNumericOperator.Sub);
return StackType.Ref;
}
}
@ -103,14 +123,51 @@ namespace ICSharpCode.Decompiler.IL @@ -103,14 +123,51 @@ namespace ICSharpCode.Decompiler.IL
protected override InstructionFlags ComputeFlags()
{
var flags = base.ComputeFlags();
if (CheckForOverflow)
if (CheckForOverflow || (Operator == BinaryNumericOperator.Div || Operator == BinaryNumericOperator.Rem))
flags |= InstructionFlags.MayThrow;
return flags;
}
public override InstructionFlags DirectFlags {
get {
if (Operator == BinaryNumericOperator.Div || Operator == BinaryNumericOperator.Rem)
return base.DirectFlags | InstructionFlags.MayThrow;
return base.DirectFlags;
}
}
string GetOperatorName(BinaryNumericOperator @operator)
{
switch (@operator) {
case BinaryNumericOperator.Add:
return "add";
case BinaryNumericOperator.Sub:
return "sub";
case BinaryNumericOperator.Mul:
return "mul";
case BinaryNumericOperator.Div:
return "div";
case BinaryNumericOperator.Rem:
return "rem";
case BinaryNumericOperator.BitAnd:
return "bit.and";
case BinaryNumericOperator.BitOr:
return "bit.or";
case BinaryNumericOperator.BitXor:
return "bit.xor";
case BinaryNumericOperator.ShiftLeft:
return "bit.shl";
case BinaryNumericOperator.ShiftRight:
return "bit.shr";
default:
throw new ArgumentOutOfRangeException();
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write("." + GetOperatorName(Operator));
if (CheckForOverflow)
output.Write(".ovf");
if (Sign == Sign.Unsigned)

19
ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs

@ -202,6 +202,25 @@ namespace ICSharpCode.Decompiler.IL @@ -202,6 +202,25 @@ namespace ICSharpCode.Decompiler.IL
return false;
}
public bool MatchBinaryNumericInstruction(BinaryNumericOperator @operator)
{
var op = this as BinaryNumericInstruction;
return op != null && op.Operator == @operator;
}
public bool MatchBinaryNumericInstruction(BinaryNumericOperator @operator, out ILInstruction left, out ILInstruction right)
{
var op = this as BinaryNumericInstruction;
if (op != null && op.Operator == @operator) {
left = op.Left;
right = op.Right;
return true;
}
left = null;
right = null;
return false;
}
/// <summary>
/// If this instruction is a conversion of the specified kind, return its argument.
/// Otherwise, return the instruction itself.

2
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -267,7 +267,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -267,7 +267,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
return parent == next;
case OpCode.SwitchInstruction:
return parent == next || (parent.OpCode == OpCode.Sub && parent.Parent == next);
return parent == next || (parent.MatchBinaryNumericInstruction(BinaryNumericOperator.Sub) && parent.Parent == next);
default:
return false;
}

Loading…
Cancel
Save