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
.WithRR(new OperatorResolveResult(left.Type, ExpressionType.Assign, left.ResolveResult, right.ResolveResult)); .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); return HandleBinaryNumeric(inst, BinaryOperatorType.Add);
} case BinaryNumericOperator.Sub:
protected internal override TranslatedExpression VisitSub(Sub inst)
{
return HandleBinaryNumeric(inst, BinaryOperatorType.Subtract); return HandleBinaryNumeric(inst, BinaryOperatorType.Subtract);
} case BinaryNumericOperator.Mul:
protected internal override TranslatedExpression VisitMul(Mul inst)
{
return HandleBinaryNumeric(inst, BinaryOperatorType.Multiply); return HandleBinaryNumeric(inst, BinaryOperatorType.Multiply);
} case BinaryNumericOperator.Div:
protected internal override TranslatedExpression VisitDiv(Div inst)
{
return HandleBinaryNumeric(inst, BinaryOperatorType.Divide); return HandleBinaryNumeric(inst, BinaryOperatorType.Divide);
} case BinaryNumericOperator.Rem:
protected internal override TranslatedExpression VisitRem(Rem inst)
{
return HandleBinaryNumeric(inst, BinaryOperatorType.Modulus); return HandleBinaryNumeric(inst, BinaryOperatorType.Modulus);
} case BinaryNumericOperator.BitAnd:
protected internal override TranslatedExpression VisitBitXor(BitXor inst)
{
return HandleBinaryNumeric(inst, BinaryOperatorType.ExclusiveOr);
}
protected internal override TranslatedExpression VisitBitAnd(BitAnd inst)
{
return HandleBinaryNumeric(inst, BinaryOperatorType.BitwiseAnd); return HandleBinaryNumeric(inst, BinaryOperatorType.BitwiseAnd);
} case BinaryNumericOperator.BitOr:
protected internal override TranslatedExpression VisitBitOr(BitOr inst)
{
return HandleBinaryNumeric(inst, BinaryOperatorType.BitwiseOr); 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) TranslatedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOperatorType op)
@ -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) TranslatedExpression HandleShift(BinaryNumericInstruction inst, BinaryOperatorType op)
{ {
var left = Translate(inst.Left); var left = Translate(inst.Left);

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

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

52
ICSharpCode.Decompiler/IL/ILReader.cs

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

442
ICSharpCode.Decompiler/IL/Instructions.cs

@ -43,22 +43,8 @@ namespace ICSharpCode.Decompiler.IL
PinnedRegion, 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> /// <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, LogicNot,
/// <summary>Adds two numbers.</summary> /// <summary>Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.</summary>
Add, BinaryNumericInstruction,
/// <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>Bitwise NOT</summary> /// <summary>Bitwise NOT</summary>
BitNot, BitNot,
/// <summary>Retrieves the RuntimeArgumentHandle.</summary> /// <summary>Retrieves the RuntimeArgumentHandle.</summary>
@ -125,10 +111,6 @@ namespace ICSharpCode.Decompiler.IL
LocAlloc, LocAlloc,
/// <summary>Returns from the current method or lambda.</summary> /// <summary>Returns from the current method or lambda.</summary>
Return, Return,
/// <summary>Shift left</summary>
Shl,
/// <summary>Shift right</summary>
Shr,
/// <summary>Load address of instance field</summary> /// <summary>Load address of instance field</summary>
LdFlda, LdFlda,
/// <summary>Load static field address</summary> /// <summary>Load static field address</summary>
@ -722,157 +704,17 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
/// <summary>Adds two numbers.</summary> /// <summary>Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.</summary>
public sealed partial class Add : BinaryNumericInstruction 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) public override void AcceptVisitor(ILVisitor visitor)
{ {
visitor.VisitMul(this); visitor.VisitBinaryNumericInstruction(this);
} }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitMul(this); return visitor.VisitBinaryNumericInstruction(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);
} }
} }
@ -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> /// <summary>Load address of instance field</summary>
public sealed partial class LdFlda : ILInstruction, IInstructionWithFieldOperand public sealed partial class LdFlda : ILInstruction, IInstructionWithFieldOperand
{ {
@ -3110,35 +2918,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
Default(inst); Default(inst);
} }
protected internal virtual void VisitAdd(Add inst) protected internal virtual void VisitBinaryNumericInstruction(BinaryNumericInstruction 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)
{ {
Default(inst); Default(inst);
} }
@ -3274,14 +3054,6 @@ namespace ICSharpCode.Decompiler.IL
{ {
Default(inst); 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) protected internal virtual void VisitLdFlda(LdFlda inst)
{ {
Default(inst); Default(inst);
@ -3404,35 +3176,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
return Default(inst); return Default(inst);
} }
protected internal virtual T VisitAdd(Add inst) protected internal virtual T VisitBinaryNumericInstruction(BinaryNumericInstruction 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)
{ {
return Default(inst); return Default(inst);
} }
@ -3568,14 +3312,6 @@ namespace ICSharpCode.Decompiler.IL
{ {
return Default(inst); 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) protected internal virtual T VisitLdFlda(LdFlda inst)
{ {
return Default(inst); return Default(inst);
@ -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 partial class BinaryComparisonInstruction
{ {
public static BinaryComparisonInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right) public static BinaryComparisonInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right)
@ -3714,14 +3419,7 @@ namespace ICSharpCode.Decompiler.IL
"Block", "Block",
"PinnedRegion", "PinnedRegion",
"logic.not", "logic.not",
"add", "binary",
"sub",
"mul",
"div",
"rem",
"bit.and",
"bit.or",
"bit.xor",
"bit.not", "bit.not",
"arglist", "arglist",
"br", "br",
@ -3755,8 +3453,6 @@ namespace ICSharpCode.Decompiler.IL
"ldmembertoken", "ldmembertoken",
"localloc", "localloc",
"ret", "ret",
"shl",
"shr",
"ldflda", "ldflda",
"ldsflda", "ldsflda",
"castclass", "castclass",
@ -3823,102 +3519,6 @@ namespace ICSharpCode.Decompiler.IL
argument = default(ILInstruction); argument = default(ILInstruction);
return false; 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) public bool MatchBitNot(out ILInstruction argument)
{ {
var inst = this as BitNot; var inst = this as BitNot;
@ -4121,30 +3721,6 @@ namespace ICSharpCode.Decompiler.IL
argument = default(ILInstruction); argument = default(ILInstruction);
return false; 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) public bool MatchLdFlda(out ILInstruction target, out IField field)
{ {
var inst = this as LdFlda; var inst = this as LdFlda;

37
ICSharpCode.Decompiler/IL/Instructions.tt

@ -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).", 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), ResultType("I4"), Unary),
new OpCode("add", "Adds two numbers.", BinaryNumeric), new OpCode("binary", "Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.",
new OpCode("sub", "Subtracts two numbers", BinaryNumeric), CustomClassName("BinaryNumericInstruction"), Binary, CustomWriteTo, CustomConstructor, CustomComputeFlags),
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("bit.not", "Bitwise NOT", Unary), new OpCode("bit.not", "Bitwise NOT", Unary),
new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")), new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
new OpCode("br", "Unconditional branch. <c>goto target;</c>", new OpCode("br", "Unconditional branch. <c>goto target;</c>",
@ -143,8 +137,6 @@
CustomClassName("LocAlloc"), Unary, ResultType("I"), MayThrow), CustomClassName("LocAlloc"), Unary, ResultType("I"), MayThrow),
new OpCode("ret", "Returns from the current method or lambda.", new OpCode("ret", "Returns from the current method or lambda.",
CustomClassName("Return"), CustomConstructor, CustomComputeFlags, MayBranch, UnconditionalBranch), 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", new OpCode("ldflda", "Load address of instance field",
CustomClassName("LdFlda"), CustomArguments("target"), MayThrowIfNotDelayed, HasFieldOperand, ResultType("Ref")), CustomClassName("LdFlda"), CustomArguments("target"), MayThrowIfNotDelayed, HasFieldOperand, ResultType("Ref")),
@ -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 partial class BinaryComparisonInstruction
{ {
public static BinaryComparisonInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right) public static BinaryComparisonInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right)
@ -565,16 +542,6 @@ namespace ICSharpCode.Decompiler.IL
opCode.WriteArguments.Add("output.Write(')');"); 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) static Action<OpCode> CustomArguments(params string[] arguments)
{ {
return CustomChildren(arguments.Select(arg => new ArgumentInfo(arg)).ToArray(), generateInline: true); 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
EvaluatesToNewValue 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> /// <summary>
/// Gets whether the instruction checks for overflow. /// Gets whether the instruction checks for overflow.
@ -45,14 +59,20 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
public readonly Sign Sign; public readonly Sign Sign;
/// <summary>
/// The operator used by this binary operator instruction.
/// </summary>
public readonly BinaryNumericOperator Operator;
readonly StackType resultType; readonly StackType resultType;
protected BinaryNumericInstruction(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) public BinaryNumericInstruction(BinaryNumericOperator op, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign)
: base(opCode, left, right) : base(OpCode.BinaryNumericInstruction, left, right)
{ {
this.CheckForOverflow = checkForOverflow; this.CheckForOverflow = checkForOverflow;
this.Sign = sign; 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(resultType != StackType.Unknown);
//Debug.Assert(CompoundAssignmentType == CompoundAssignmentType.None || IsValidCompoundAssignmentTarget(Left)); //Debug.Assert(CompoundAssignmentType == CompoundAssignmentType.None || IsValidCompoundAssignmentTarget(Left));
} }
@ -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 // Based on Table 2: Binary Numeric Operations
// also works for Table 5: Integer Operations // also works for Table 5: Integer Operations
// and for Table 7: Overflow Arithmetic 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 // Shift op codes use Table 6
return left; return left;
} }
if (left == StackType.Ref || right == StackType.Ref) { if (left == StackType.Ref || right == StackType.Ref) {
if (left == StackType.Ref && right == StackType.Ref) { if (left == StackType.Ref && right == StackType.Ref) {
// sub(&, &) = I // sub(&, &) = I
Debug.Assert(opCode == OpCode.Sub); Debug.Assert(op == BinaryNumericOperator.Sub);
return StackType.I; return StackType.I;
} else { } else {
// add/sub with I or I4 and & // 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; return StackType.Ref;
} }
} }
@ -103,14 +123,51 @@ namespace ICSharpCode.Decompiler.IL
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
var flags = base.ComputeFlags(); var flags = base.ComputeFlags();
if (CheckForOverflow) if (CheckForOverflow || (Operator == BinaryNumericOperator.Div || Operator == BinaryNumericOperator.Rem))
flags |= InstructionFlags.MayThrow; flags |= InstructionFlags.MayThrow;
return flags; 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) public override void WriteTo(ITextOutput output)
{ {
output.Write(OpCode); output.Write(OpCode);
output.Write("." + GetOperatorName(Operator));
if (CheckForOverflow) if (CheckForOverflow)
output.Write(".ovf"); output.Write(".ovf");
if (Sign == Sign.Unsigned) if (Sign == Sign.Unsigned)

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

@ -202,6 +202,25 @@ namespace ICSharpCode.Decompiler.IL
return false; 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> /// <summary>
/// If this instruction is a conversion of the specified kind, return its argument. /// If this instruction is a conversion of the specified kind, return its argument.
/// Otherwise, return the instruction itself. /// Otherwise, return the instruction itself.

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

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

Loading…
Cancel
Save