diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index c41db8776..0be2835dc 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -216,7 +216,7 @@ namespace ICSharpCode.Decompiler.CSharp return LogicNot(IsType((IsInst)inst.Left)); } else if (inst.Right.OpCode == OpCode.IsInst && inst.Left.OpCode == OpCode.LdNull) { return LogicNot(IsType((IsInst)inst.Right)); - } + } var left = ConvertArgument(inst.Left); var right = ConvertArgument(inst.Right); return new ConvertedExpression( @@ -262,6 +262,58 @@ namespace ICSharpCode.Decompiler.CSharp left.Type); } + protected internal override ConvertedExpression VisitAdd(Add inst) + { + return HandleBinaryNumeric(inst, BinaryOperatorType.Add); + } + + protected internal override ConvertedExpression VisitSub(Sub inst) + { + return HandleBinaryNumeric(inst, BinaryOperatorType.Subtract); + } + + protected internal override ConvertedExpression VisitBitXor(BitXor inst) + { + return HandleBinaryNumeric(inst, BinaryOperatorType.ExclusiveOr); + } + + protected internal override ConvertedExpression VisitShl(Shl inst) + { + return HandleBinaryNumeric(inst, BinaryOperatorType.ShiftLeft); + } + + protected internal override ConvertedExpression VisitShr(Shr inst) + { + return HandleBinaryNumeric(inst, BinaryOperatorType.ShiftRight); + } + + ConvertedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOperatorType op) + { + var left = ConvertArgument(inst.Left); + var right = ConvertArgument(inst.Right); + var rr = resolver.ResolveBinaryOperator(op, new ResolveResult(left.Type), new ResolveResult(right.Type)); + if (!rr.IsError && rr.Type.GetStackType() == inst.ResultType + && IsCompatibleWithSign(left.Type, inst.Sign) && IsCompatibleWithSign(right.Type, inst.Sign)) + { + return new ConvertedExpression( + new BinaryOperatorExpression(left.Expression, op, right.Expression), + rr.Type); + } + IType targetType = compilation.FindType(inst.ResultType.ToKnownTypeCode(inst.Sign)); + return new ConvertedExpression( + new BinaryOperatorExpression(left.ConvertTo(targetType, this), op, right.ConvertTo(targetType, this)), + targetType); + } + + /// + /// Gets whether has the specified . + /// If is None, always returns true. + /// + bool IsCompatibleWithSign(IType type, Sign sign) + { + return sign == Sign.None || type.GetSign() == sign; + } + protected internal override ConvertedExpression VisitCall(Call inst) { return HandleCallInstruction(inst); diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 9df7331ec..ef6387b81 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -90,6 +90,7 @@ + diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 85a9da580..95953d0a8 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -188,11 +188,11 @@ namespace ICSharpCode.Decompiler.IL switch (stack.PeekOrDefault()) { case StackType.I4: case StackType.I: - return new Sub(new LdcI4(0), Pop(), OverflowMode.None); + return new Sub(new LdcI4(0), Pop(), checkForOverflow: false, sign: Sign.None); case StackType.I8: - return new Sub(new LdcI8(0), Pop(), OverflowMode.None); + return new Sub(new LdcI8(0), Pop(), checkForOverflow: false, sign: Sign.None); case StackType.F: - return new Sub(new LdcF(0), Pop(), OverflowMode.None); + return new Sub(new LdcF(0), Pop(), checkForOverflow: false, sign: Sign.None); default: Warn("Unsupported input type for neg: "); goto case StackType.I4; @@ -216,9 +216,9 @@ namespace ICSharpCode.Decompiler.IL case ILOpCode.Add: return BinaryNumeric(OpCode.Add); case ILOpCode.Add_Ovf: - return BinaryNumeric(OpCode.Add, OverflowMode.Ovf); + return BinaryNumeric(OpCode.Add, true, Sign.Signed); case ILOpCode.Add_Ovf_Un: - return BinaryNumeric(OpCode.Add, OverflowMode.Ovf_Un); + return BinaryNumeric(OpCode.Add, true, Sign.Unsigned); case ILOpCode.And: return BinaryNumeric(OpCode.BitAnd); case ILOpCode.Arglist: @@ -296,77 +296,77 @@ namespace ICSharpCode.Decompiler.IL case ILOpCode.Ckfinite: return new Ckfinite(); case ILOpCode.Conv_I1: - return new Conv(Pop(), PrimitiveType.I1, OverflowMode.None); + return new Conv(Pop(), PrimitiveType.I1, false, Sign.None); case ILOpCode.Conv_I2: - return new Conv(Pop(), PrimitiveType.I2, OverflowMode.None); + return new Conv(Pop(), PrimitiveType.I2, false, Sign.None); case ILOpCode.Conv_I4: - return new Conv(Pop(), PrimitiveType.I4, OverflowMode.None); + return new Conv(Pop(), PrimitiveType.I4, false, Sign.None); case ILOpCode.Conv_I8: - return new Conv(Pop(), PrimitiveType.I8, OverflowMode.None); + return new Conv(Pop(), PrimitiveType.I8, false, Sign.None); case ILOpCode.Conv_R4: - return new Conv(Pop(), PrimitiveType.R4, OverflowMode.None); + return new Conv(Pop(), PrimitiveType.R4, false, Sign.Signed); case ILOpCode.Conv_R8: - return new Conv(Pop(), PrimitiveType.R8, OverflowMode.None); + return new Conv(Pop(), PrimitiveType.R8, false, Sign.Signed); case ILOpCode.Conv_U1: - return new Conv(Pop(), PrimitiveType.U1, OverflowMode.None); + return new Conv(Pop(), PrimitiveType.U1, false, Sign.None); case ILOpCode.Conv_U2: - return new Conv(Pop(), PrimitiveType.U2, OverflowMode.None); + return new Conv(Pop(), PrimitiveType.U2, false, Sign.None); case ILOpCode.Conv_U4: - return new Conv(Pop(), PrimitiveType.U4, OverflowMode.None); + return new Conv(Pop(), PrimitiveType.U4, false, Sign.None); case ILOpCode.Conv_U8: - return new Conv(Pop(), PrimitiveType.U8, OverflowMode.None); + return new Conv(Pop(), PrimitiveType.U8, false, Sign.None); case ILOpCode.Conv_I: - return new Conv(Pop(), PrimitiveType.I, OverflowMode.None); + return new Conv(Pop(), PrimitiveType.I, false, Sign.None); case ILOpCode.Conv_U: - return new Conv(Pop(), PrimitiveType.U, OverflowMode.None); + return new Conv(Pop(), PrimitiveType.U, false, Sign.None); case ILOpCode.Conv_R_Un: - return new Conv(Pop(), PrimitiveType.R8, OverflowMode.Un); + return new Conv(Pop(), PrimitiveType.R8, false, Sign.Unsigned); case ILOpCode.Conv_Ovf_I1: - return new Conv(Pop(), PrimitiveType.I1, OverflowMode.Ovf); + return new Conv(Pop(), PrimitiveType.I1, true, Sign.Signed); case ILOpCode.Conv_Ovf_I2: - return new Conv(Pop(), PrimitiveType.I2, OverflowMode.Ovf); + return new Conv(Pop(), PrimitiveType.I2, true, Sign.Signed); case ILOpCode.Conv_Ovf_I4: - return new Conv(Pop(), PrimitiveType.I4, OverflowMode.Ovf); + return new Conv(Pop(), PrimitiveType.I4, true, Sign.Signed); case ILOpCode.Conv_Ovf_I8: - return new Conv(Pop(), PrimitiveType.I8, OverflowMode.Ovf); + return new Conv(Pop(), PrimitiveType.I8, true, Sign.Signed); case ILOpCode.Conv_Ovf_U1: - return new Conv(Pop(), PrimitiveType.U1, OverflowMode.Ovf); + return new Conv(Pop(), PrimitiveType.U1, true, Sign.Signed); case ILOpCode.Conv_Ovf_U2: - return new Conv(Pop(), PrimitiveType.U2, OverflowMode.Ovf); + return new Conv(Pop(), PrimitiveType.U2, true, Sign.Signed); case ILOpCode.Conv_Ovf_U4: - return new Conv(Pop(), PrimitiveType.U4, OverflowMode.Ovf); + return new Conv(Pop(), PrimitiveType.U4, true, Sign.Signed); case ILOpCode.Conv_Ovf_U8: - return new Conv(Pop(), PrimitiveType.U8, OverflowMode.Ovf); + return new Conv(Pop(), PrimitiveType.U8, true, Sign.Signed); case ILOpCode.Conv_Ovf_I: - return new Conv(Pop(), PrimitiveType.I, OverflowMode.Ovf); + return new Conv(Pop(), PrimitiveType.I, true, Sign.Signed); case ILOpCode.Conv_Ovf_U: - return new Conv(Pop(), PrimitiveType.U, OverflowMode.Ovf); + return new Conv(Pop(), PrimitiveType.U, true, Sign.Signed); case ILOpCode.Conv_Ovf_I1_Un: - return new Conv(Pop(), PrimitiveType.I1, OverflowMode.Ovf_Un); + return new Conv(Pop(), PrimitiveType.I1, true, Sign.Unsigned); case ILOpCode.Conv_Ovf_I2_Un: - return new Conv(Pop(), PrimitiveType.I2, OverflowMode.Ovf_Un); + return new Conv(Pop(), PrimitiveType.I2, true, Sign.Unsigned); case ILOpCode.Conv_Ovf_I4_Un: - return new Conv(Pop(), PrimitiveType.I4, OverflowMode.Ovf_Un); + return new Conv(Pop(), PrimitiveType.I4, true, Sign.Unsigned); case ILOpCode.Conv_Ovf_I8_Un: - return new Conv(Pop(), PrimitiveType.I8, OverflowMode.Ovf_Un); + return new Conv(Pop(), PrimitiveType.I8, true, Sign.Unsigned); case ILOpCode.Conv_Ovf_U1_Un: - return new Conv(Pop(), PrimitiveType.U1, OverflowMode.Ovf_Un); + return new Conv(Pop(), PrimitiveType.U1, true, Sign.Unsigned); case ILOpCode.Conv_Ovf_U2_Un: - return new Conv(Pop(), PrimitiveType.U2, OverflowMode.Ovf_Un); + return new Conv(Pop(), PrimitiveType.U2, true, Sign.Unsigned); case ILOpCode.Conv_Ovf_U4_Un: - return new Conv(Pop(), PrimitiveType.U4, OverflowMode.Ovf_Un); + return new Conv(Pop(), PrimitiveType.U4, true, Sign.Unsigned); case ILOpCode.Conv_Ovf_U8_Un: - return new Conv(Pop(), PrimitiveType.U8, OverflowMode.Ovf_Un); + return new Conv(Pop(), PrimitiveType.U8, true, Sign.Unsigned); case ILOpCode.Conv_Ovf_I_Un: - return new Conv(Pop(), PrimitiveType.I, OverflowMode.Ovf_Un); + return new Conv(Pop(), PrimitiveType.I, true, Sign.Unsigned); case ILOpCode.Conv_Ovf_U_Un: - return new Conv(Pop(), PrimitiveType.U, OverflowMode.Ovf_Un); + return new Conv(Pop(), PrimitiveType.U, true, Sign.Unsigned); case ILOpCode.Cpblk: throw new NotImplementedException(); case ILOpCode.Div: - return BinaryNumeric(OpCode.Div, OverflowMode.None); + return BinaryNumeric(OpCode.Div, false, Sign.Signed); case ILOpCode.Div_Un: - return BinaryNumeric(OpCode.Div, OverflowMode.Un); + return BinaryNumeric(OpCode.Div, false, Sign.Unsigned); case ILOpCode.Dup: return new Peek(stack.Count > 0 ? stack.Peek() : StackType.Unknown); case ILOpCode.Endfilter: @@ -458,11 +458,11 @@ namespace ICSharpCode.Decompiler.IL case ILOpCode.Localloc: return new LocAlloc(Pop()); case ILOpCode.Mul: - return BinaryNumeric(OpCode.Mul, OverflowMode.None); + return BinaryNumeric(OpCode.Mul, false, Sign.None); case ILOpCode.Mul_Ovf: - return BinaryNumeric(OpCode.Mul, OverflowMode.Ovf); + return BinaryNumeric(OpCode.Mul, true, Sign.Signed); case ILOpCode.Mul_Ovf_Un: - return BinaryNumeric(OpCode.Mul, OverflowMode.Ovf_Un); + return BinaryNumeric(OpCode.Mul, true, Sign.Unsigned); case ILOpCode.Neg: return Neg(); case ILOpCode.Newobj: @@ -476,17 +476,17 @@ namespace ICSharpCode.Decompiler.IL case ILOpCode.Pop: return new Void(Pop()); case ILOpCode.Rem: - return BinaryNumeric(OpCode.Rem, OverflowMode.None); + return BinaryNumeric(OpCode.Rem, false, Sign.Signed); case ILOpCode.Rem_Un: - return BinaryNumeric(OpCode.Rem, OverflowMode.Un); + return BinaryNumeric(OpCode.Rem, false, Sign.Unsigned); case ILOpCode.Ret: return Return(); case ILOpCode.Shl: - return BinaryNumeric(OpCode.Shl, OverflowMode.None); + return BinaryNumeric(OpCode.Shl, false, Sign.None); case ILOpCode.Shr: - return BinaryNumeric(OpCode.Shr, OverflowMode.None); + return BinaryNumeric(OpCode.Shr, false, Sign.Signed); case ILOpCode.Shr_Un: - return BinaryNumeric(OpCode.Shr, OverflowMode.Un); + return BinaryNumeric(OpCode.Shr, false, Sign.Unsigned); case ILOpCode.Starg: return Starg(reader.ReadUInt16()); case ILOpCode.Starg_S: @@ -517,11 +517,11 @@ namespace ICSharpCode.Decompiler.IL case ILOpCode.Stloc_3: return Stloc(ilOpCode - ILOpCode.Stloc_0); case ILOpCode.Sub: - return BinaryNumeric(OpCode.Sub); + return BinaryNumeric(OpCode.Sub, false, Sign.None); case ILOpCode.Sub_Ovf: - return BinaryNumeric(OpCode.Sub, OverflowMode.Ovf); + return BinaryNumeric(OpCode.Sub, true, Sign.Signed); case ILOpCode.Sub_Ovf_Un: - return BinaryNumeric(OpCode.Sub, OverflowMode.Ovf_Un); + return BinaryNumeric(OpCode.Sub, true, Sign.Unsigned); case ILOpCode.Switch: throw new NotImplementedException(); case ILOpCode.Xor: @@ -793,11 +793,11 @@ namespace ICSharpCode.Decompiler.IL } } - ILInstruction BinaryNumeric(OpCode opCode, OverflowMode overflowMode = OverflowMode.None) + ILInstruction BinaryNumeric(OpCode opCode, bool checkForOverflow = false, Sign sign = Sign.None) { var right = Pop(); var left = Pop(); - return BinaryNumericInstruction.Create(opCode, left, right, overflowMode); + return BinaryNumericInstruction.Create(opCode, left, right, checkForOverflow, sign); } } } diff --git a/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs b/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs index e055f8d52..e7d673084 100644 --- a/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs +++ b/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs @@ -40,13 +40,5 @@ namespace ICSharpCode.Decompiler.IL { output.Write(primitiveType.ToString().ToLowerInvariant()); } - - public static void WriteSuffix(this ITextOutput output, OverflowMode mode) - { - if ((mode & OverflowMode.Ovf) != 0) - output.Write(".ovf"); - if ((mode & OverflowMode.Un) != 0) - output.Write(".un"); - } } } diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index 9e8e11b31..2138a17c3 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -393,7 +393,7 @@ namespace ICSharpCode.Decompiler.IL /// Adds two numbers. public sealed partial class Add : BinaryNumericInstruction { - public Add(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Add, left, right, overflowMode) + public Add(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Add, left, right, checkForOverflow, sign) { } @@ -406,7 +406,7 @@ namespace ICSharpCode.Decompiler.IL /// Subtracts two numbers public sealed partial class Sub : BinaryNumericInstruction { - public Sub(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Sub, left, right, overflowMode) + public Sub(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Sub, left, right, checkForOverflow, sign) { } @@ -419,7 +419,7 @@ namespace ICSharpCode.Decompiler.IL /// Multiplies two numbers public sealed partial class Mul : BinaryNumericInstruction { - public Mul(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Mul, left, right, overflowMode) + public Mul(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Mul, left, right, checkForOverflow, sign) { } @@ -432,7 +432,7 @@ namespace ICSharpCode.Decompiler.IL /// Divides two numbers public sealed partial class Div : BinaryNumericInstruction { - public Div(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Div, left, right, overflowMode) + public Div(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Div, left, right, checkForOverflow, sign) { } @@ -449,7 +449,7 @@ namespace ICSharpCode.Decompiler.IL /// Division remainder public sealed partial class Rem : BinaryNumericInstruction { - public Rem(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Rem, left, right, overflowMode) + public Rem(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Rem, left, right, checkForOverflow, sign) { } @@ -466,7 +466,7 @@ namespace ICSharpCode.Decompiler.IL /// Bitwise AND public sealed partial class BitAnd : BinaryNumericInstruction { - public BitAnd(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.BitAnd, left, right, overflowMode) + public BitAnd(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.BitAnd, left, right, checkForOverflow, sign) { } @@ -479,7 +479,7 @@ namespace ICSharpCode.Decompiler.IL /// Bitwise OR public sealed partial class BitOr : BinaryNumericInstruction { - public BitOr(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.BitOr, left, right, overflowMode) + public BitOr(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.BitOr, left, right, checkForOverflow, sign) { } @@ -492,7 +492,7 @@ namespace ICSharpCode.Decompiler.IL /// Bitwise XOR public sealed partial class BitXor : BinaryNumericInstruction { - public BitXor(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.BitXor, left, right, overflowMode) + public BitXor(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.BitXor, left, right, checkForOverflow, sign) { } @@ -1122,7 +1122,7 @@ namespace ICSharpCode.Decompiler.IL /// Shift left public sealed partial class Shl : BinaryNumericInstruction { - public Shl(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Shl, left, right, overflowMode) + public Shl(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Shl, left, right, checkForOverflow, sign) { } @@ -1135,7 +1135,7 @@ namespace ICSharpCode.Decompiler.IL /// Shift right public sealed partial class Shr : BinaryNumericInstruction { - public Shr(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Shr, left, right, overflowMode) + public Shr(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Shr, left, right, checkForOverflow, sign) { } @@ -2272,29 +2272,29 @@ namespace ICSharpCode.Decompiler.IL partial class BinaryNumericInstruction { - public static BinaryNumericInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right, OverflowMode overflowMode) + public static BinaryNumericInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) { switch (opCode) { case OpCode.Add: - return new Add(left, right, overflowMode); + return new Add(left, right, checkForOverflow, sign); case OpCode.Sub: - return new Sub(left, right, overflowMode); + return new Sub(left, right, checkForOverflow, sign); case OpCode.Mul: - return new Mul(left, right, overflowMode); + return new Mul(left, right, checkForOverflow, sign); case OpCode.Div: - return new Div(left, right, overflowMode); + return new Div(left, right, checkForOverflow, sign); case OpCode.Rem: - return new Rem(left, right, overflowMode); + return new Rem(left, right, checkForOverflow, sign); case OpCode.BitAnd: - return new BitAnd(left, right, overflowMode); + return new BitAnd(left, right, checkForOverflow, sign); case OpCode.BitOr: - return new BitOr(left, right, overflowMode); + return new BitOr(left, right, checkForOverflow, sign); case OpCode.BitXor: - return new BitXor(left, right, overflowMode); + return new BitXor(left, right, checkForOverflow, sign); case OpCode.Shl: - return new Shl(left, right, overflowMode); + return new Shl(left, right, checkForOverflow, sign); case OpCode.Shr: - return new Shr(left, right, overflowMode); + return new Shr(left, right, checkForOverflow, sign); default: throw new ArgumentException("opCode is not a binary numeric instruction"); } diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index 08aff0c94..ecf1e05a6 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -248,12 +248,12 @@ namespace ICSharpCode.Decompiler.IL partial class BinaryNumericInstruction { - public static BinaryNumericInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right, OverflowMode overflowMode) + 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, overflowMode); + return new <#=opCode.Name#>(left, right, checkForOverflow, sign); <# } #> default: throw new ArgumentException("opCode is not a binary numeric instruction"); @@ -477,9 +477,12 @@ namespace ICSharpCode.Decompiler.IL static Action BinaryNumeric = opCode => { Binary(opCode); opCode.BaseClass = "BinaryNumericInstruction"; - opCode.ConstructorParameters.Add("OverflowMode overflowMode"); - opCode.BaseConstructorArguments.Add("overflowMode"); - opCode.WriteOpCodeSuffix.Add("output.WriteSuffix(overflowMode);"); + opCode.ConstructorParameters.Add("bool checkForOverflow"); + opCode.BaseConstructorArguments.Add("checkForOverflow"); + opCode.WriteOpCodeSuffix.Add("if (checkForOverflow) output.Write(\".ovf\");"); + opCode.ConstructorParameters.Add("Sign sign"); + opCode.BaseConstructorArguments.Add("sign"); + opCode.WriteOpCodeSuffix.Add("if (sign == Sign.Unsigned) output.Write(\".un\");"); }; // BinaryNumeric trait: the instruction is derived from BinaryComparisonInstruction. Implies Binary and I4Result. diff --git a/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs index 62eff22ec..2a656f65e 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs @@ -24,29 +24,27 @@ using System.Text; using System.Threading.Tasks; namespace ICSharpCode.Decompiler.IL { - [Flags] - public enum OverflowMode : byte - { - /// Don't check for overflow, treat integers as signed. - None = 0, - /// Check for overflow, treat integers as signed. - Ovf = 1, - /// Don't check for overflow, treat integers as unsigned. - Un = 2, - /// Check for overflow, treat integers as unsigned. - Ovf_Un = 3 - } - public abstract partial class BinaryNumericInstruction : BinaryInstruction { - public readonly OverflowMode OverflowMode; + /// + /// Gets whether the instruction checks for overflow. + /// + public readonly bool CheckForOverflow; + + /// + /// For integer operations that depend on the sign, specifies whether the operation + /// is signed or unsigned. + /// For instructions that produce the same result for either sign, returns Sign.None. + /// + public readonly Sign Sign; readonly StackType resultType; - protected BinaryNumericInstruction(OpCode opCode, ILInstruction left, ILInstruction right, OverflowMode overflowMode) + protected BinaryNumericInstruction(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(opCode, left, right) { - this.OverflowMode = overflowMode; + this.CheckForOverflow = checkForOverflow; + this.Sign = sign; this.resultType = ComputeResultType(opCode, left.ResultType, right.ResultType); } @@ -83,7 +81,7 @@ namespace ICSharpCode.Decompiler.IL protected override InstructionFlags ComputeFlags() { var flags = base.ComputeFlags(); - if ((OverflowMode & OverflowMode.Ovf) != 0) + if (CheckForOverflow) flags |= InstructionFlags.MayThrow; return flags; } @@ -91,7 +89,12 @@ namespace ICSharpCode.Decompiler.IL public override void WriteTo(ITextOutput output) { output.Write(OpCode); - output.WriteSuffix(OverflowMode); + if (CheckForOverflow) + output.Write(".ovf"); + if (Sign == Sign.Unsigned) + output.Write(".unsigned"); + else if (Sign == Sign.Signed) + output.Write(".signed"); output.Write('('); Left.WriteTo(output); output.Write(", "); diff --git a/ICSharpCode.Decompiler/IL/Instructions/Conv.cs b/ICSharpCode.Decompiler/IL/Instructions/Conv.cs index 4b8dea48f..106e8811b 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Conv.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Conv.cs @@ -23,12 +23,18 @@ namespace ICSharpCode.Decompiler.IL partial class Conv : UnaryInstruction { public readonly PrimitiveType TargetType; - public readonly OverflowMode ConvMode; + public readonly bool CheckForOverflow; - public Conv(ILInstruction argument, PrimitiveType targetType, OverflowMode convMode) : base(OpCode.Conv, argument) + /// + /// Gets the sign of the input type. + /// + public readonly Sign Sign; + + public Conv(ILInstruction argument, PrimitiveType targetType, bool checkForOverflow, Sign sign) : base(OpCode.Conv, argument) { this.TargetType = targetType; - this.ConvMode = convMode; + this.CheckForOverflow = checkForOverflow; + this.Sign = sign; } public override StackType ResultType { @@ -38,7 +44,12 @@ namespace ICSharpCode.Decompiler.IL public override void WriteTo(ITextOutput output) { output.Write(OpCode); - output.WriteSuffix(ConvMode); + if (CheckForOverflow) + output.Write(".ovf"); + if (Sign == Sign.Unsigned) + output.Write(".unsigned"); + else if (Sign == Sign.Signed) + output.Write(".signed"); output.Write(' '); output.Write(Argument.ResultType); output.Write("->"); @@ -51,7 +62,7 @@ namespace ICSharpCode.Decompiler.IL protected override InstructionFlags ComputeFlags() { var flags = base.ComputeFlags(); - if ((ConvMode & OverflowMode.Ovf) != 0) + if (CheckForOverflow) flags |= InstructionFlags.MayThrow; return flags; } diff --git a/ICSharpCode.Decompiler/IL/NRTypeExtensions.cs b/ICSharpCode.Decompiler/IL/NRTypeExtensions.cs new file mode 100644 index 000000000..e4a321f04 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/NRTypeExtensions.cs @@ -0,0 +1,125 @@ +// Copyright (c) 2014 Daniel Grunwald +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.Decompiler.IL +{ + public static class NRTypeExtensions + { + public static StackType GetStackType(this IType type) + { + switch (type.Kind) + { + case TypeKind.Unknown: + return StackType.Unknown; + case TypeKind.ByReference: + return StackType.Ref; + case TypeKind.Pointer: + return StackType.I; + } + ITypeDefinition typeDef = type.GetDefinition(); + if (typeDef == null) + return StackType.O; + if (typeDef.Kind == TypeKind.Enum) { + typeDef = typeDef.EnumUnderlyingType.GetDefinition(); + if (typeDef == null) + return StackType.O; + } + switch (typeDef.KnownTypeCode) { + case KnownTypeCode.Boolean: + case KnownTypeCode.Char: + case KnownTypeCode.SByte: + case KnownTypeCode.Byte: + case KnownTypeCode.Int16: + case KnownTypeCode.UInt16: + case KnownTypeCode.Int32: + case KnownTypeCode.UInt32: + return StackType.I4; + case KnownTypeCode.Int64: + case KnownTypeCode.UInt64: + return StackType.I8; + case KnownTypeCode.Single: + case KnownTypeCode.Double: + return StackType.F; + case KnownTypeCode.Void: + return StackType.Void; + case KnownTypeCode.IntPtr: + case KnownTypeCode.UIntPtr: + return StackType.I; + default: + return StackType.O; + } + } + + public static Sign GetSign(this IType type) + { + var typeDef = type.GetDefinition(); + if (typeDef == null) + return Sign.None; + switch (typeDef.KnownTypeCode) { + case KnownTypeCode.SByte: + case KnownTypeCode.Int16: + case KnownTypeCode.Int32: + case KnownTypeCode.Int64: + case KnownTypeCode.IntPtr: + case KnownTypeCode.Single: + case KnownTypeCode.Double: + case KnownTypeCode.Decimal: + return Sign.Signed; + case KnownTypeCode.UIntPtr: + case KnownTypeCode.Char: + case KnownTypeCode.Byte: + case KnownTypeCode.UInt16: + case KnownTypeCode.UInt32: + case KnownTypeCode.UInt64: + return Sign.Unsigned; + default: + return Sign.None; + } + } + + public static KnownTypeCode ToKnownTypeCode(this StackType stackType, Sign sign = Sign.None) + { + switch (stackType) { + case StackType.I4: + return sign == Sign.Unsigned ? KnownTypeCode.UInt32 : KnownTypeCode.Int32; + case StackType.I8: + return sign == Sign.Unsigned ? KnownTypeCode.UInt64 : KnownTypeCode.Int64; + case StackType.I: + return sign == Sign.Unsigned ? KnownTypeCode.UIntPtr : KnownTypeCode.IntPtr; + case StackType.F: + return KnownTypeCode.Double; + case StackType.O: + return KnownTypeCode.Object; + case StackType.Void: + return KnownTypeCode.Void; + default: + return KnownTypeCode.None; + } + } + } + + public enum Sign + { + None, + Signed, + Unsigned + } +} diff --git a/ICSharpCode.Decompiler/IL/StackType.cs b/ICSharpCode.Decompiler/IL/StackType.cs index 89c353365..e5cac8101 100644 --- a/ICSharpCode.Decompiler/IL/StackType.cs +++ b/ICSharpCode.Decompiler/IL/StackType.cs @@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.IL I4, /// 64-bit integer I8, - /// native-size integer + /// native-size integer, or unmanaged pointer I, /// Floating point number F, diff --git a/ILSpy/Properties/AssemblyInfo.template.cs b/ILSpy/Properties/AssemblyInfo.template.cs index 3a392ca5a..c05ed222d 100644 --- a/ILSpy/Properties/AssemblyInfo.template.cs +++ b/ILSpy/Properties/AssemblyInfo.template.cs @@ -31,8 +31,8 @@ using System.Runtime.InteropServices; internal static class RevisionClass { - public const string Major = "2"; - public const string Minor = "1"; + public const string Major = "3"; + public const string Minor = "0"; public const string Build = "0"; public const string Revision = "$INSERTREVISION$"; public const string VersionName = null;