diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 2109bad73..a90ab5c00 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -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) - { - return HandleBinaryNumeric(inst, BinaryOperatorType.Add); - } - - protected internal override TranslatedExpression VisitSub(Sub inst) - { - return HandleBinaryNumeric(inst, BinaryOperatorType.Subtract); - } - - protected internal override TranslatedExpression VisitMul(Mul inst) - { - return HandleBinaryNumeric(inst, BinaryOperatorType.Multiply); - } - - protected internal override TranslatedExpression VisitDiv(Div inst) - { - return HandleBinaryNumeric(inst, BinaryOperatorType.Divide); - } - - protected internal override TranslatedExpression VisitRem(Rem inst) - { - return HandleBinaryNumeric(inst, BinaryOperatorType.Modulus); - } - - protected internal override TranslatedExpression VisitBitXor(BitXor inst) - { - return HandleBinaryNumeric(inst, BinaryOperatorType.ExclusiveOr); - } - - protected internal override TranslatedExpression VisitBitAnd(BitAnd inst) - { - return HandleBinaryNumeric(inst, BinaryOperatorType.BitwiseAnd); - } - - protected internal override TranslatedExpression VisitBitOr(BitOr inst) - { - return HandleBinaryNumeric(inst, BinaryOperatorType.BitwiseOr); + protected internal override TranslatedExpression VisitBinaryNumericInstruction(BinaryNumericInstruction inst) + { + switch (inst.Operator) { + case BinaryNumericOperator.Add: + return HandleBinaryNumeric(inst, BinaryOperatorType.Add); + case BinaryNumericOperator.Sub: + return HandleBinaryNumeric(inst, BinaryOperatorType.Subtract); + case BinaryNumericOperator.Mul: + return HandleBinaryNumeric(inst, BinaryOperatorType.Multiply); + case BinaryNumericOperator.Div: + return HandleBinaryNumeric(inst, BinaryOperatorType.Divide); + case BinaryNumericOperator.Rem: + return HandleBinaryNumeric(inst, BinaryOperatorType.Modulus); + case BinaryNumericOperator.BitAnd: + return HandleBinaryNumeric(inst, BinaryOperatorType.BitwiseAnd); + 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 } } - 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); diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs b/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs index 743455711..6485990ed 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs @@ -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); diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index e4bf3d963..909553ceb 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -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 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 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 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 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 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 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 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) diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index 23715522b..099991e4f 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -43,22 +43,8 @@ namespace ICSharpCode.Decompiler.IL PinnedRegion, /// 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). LogicNot, - /// Adds two numbers. - Add, - /// Subtracts two numbers - Sub, - /// Multiplies two numbers - Mul, - /// Divides two numbers - Div, - /// Division remainder - Rem, - /// Bitwise AND - BitAnd, - /// Bitwise OR - BitOr, - /// Bitwise XOR - BitXor, + /// Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr. + BinaryNumericInstruction, /// Bitwise NOT BitNot, /// Retrieves the RuntimeArgumentHandle. @@ -125,10 +111,6 @@ namespace ICSharpCode.Decompiler.IL LocAlloc, /// Returns from the current method or lambda. Return, - /// Shift left - Shl, - /// Shift right - Shr, /// Load address of instance field LdFlda, /// Load static field address @@ -722,157 +704,17 @@ namespace ICSharpCode.Decompiler.IL } } - /// Adds two numbers. - public sealed partial class Add : BinaryNumericInstruction + /// Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr. + 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(ILVisitor visitor) - { - return visitor.VisitAdd(this); - } - } - - /// Subtracts two numbers - 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(ILVisitor visitor) - { - return visitor.VisitSub(this); - } - } - - /// Multiplies two numbers - 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(ILVisitor visitor) { - return visitor.VisitMul(this); - } - } - - /// Divides two numbers - 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(ILVisitor visitor) - { - return visitor.VisitDiv(this); - } - } - - /// Division remainder - 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(ILVisitor visitor) - { - return visitor.VisitRem(this); - } - } - - /// Bitwise AND - 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(ILVisitor visitor) - { - return visitor.VisitBitAnd(this); - } - } - - /// Bitwise OR - 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(ILVisitor visitor) - { - return visitor.VisitBitOr(this); - } - } - - /// Bitwise XOR - 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(ILVisitor visitor) - { - return visitor.VisitBitXor(this); + return visitor.VisitBinaryNumericInstruction(this); } } @@ -1985,40 +1827,6 @@ namespace ICSharpCode.Decompiler.IL } } - /// Shift left - 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(ILVisitor visitor) - { - return visitor.VisitShl(this); - } - } - - /// Shift right - 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(ILVisitor visitor) - { - return visitor.VisitShr(this); - } - } - /// Load address of instance field public sealed partial class LdFlda : ILInstruction, IInstructionWithFieldOperand { @@ -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 { 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 { 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 { 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 } } - 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 "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 "ldmembertoken", "localloc", "ret", - "shl", - "shr", "ldflda", "ldsflda", "castclass", @@ -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 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; diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index 8f745e076..96ed0bc88 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/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).", 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. goto target;", @@ -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 <# } #> } - 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) @@ -564,16 +541,6 @@ namespace ICSharpCode.Decompiler.IL opCode.WriteArguments.Add("Right.WriteTo(output);"); 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 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 CustomArguments(params string[] arguments) { diff --git a/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs index 9be3a53c8..74c63f283 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs @@ -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 { /// /// Gets whether the instruction checks for overflow. @@ -44,15 +58,21 @@ namespace ICSharpCode.Decompiler.IL /// For instructions that produce the same result for either sign, returns Sign.None. /// public readonly Sign Sign; - + + /// + /// The operator used by this binary operator instruction. + /// + 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 } } - 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 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) diff --git a/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs b/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs index 128b525da..c728c5650 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs @@ -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; + } + /// /// If this instruction is a conversion of the specified kind, return its argument. /// Otherwise, return the instruction itself. diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs index 09e76282c..70b69c3ed 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs @@ -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; }