Browse Source

Instead of OverflowMode, use bool checkForOverflow + Sign

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
3d47e1028e
  1. 54
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  3. 106
      ICSharpCode.Decompiler/IL/ILReader.cs
  4. 8
      ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs
  5. 42
      ICSharpCode.Decompiler/IL/Instructions.cs
  6. 13
      ICSharpCode.Decompiler/IL/Instructions.tt
  7. 39
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  8. 21
      ICSharpCode.Decompiler/IL/Instructions/Conv.cs
  9. 125
      ICSharpCode.Decompiler/IL/NRTypeExtensions.cs
  10. 2
      ICSharpCode.Decompiler/IL/StackType.cs
  11. 4
      ILSpy/Properties/AssemblyInfo.template.cs

54
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -216,7 +216,7 @@ namespace ICSharpCode.Decompiler.CSharp
return LogicNot(IsType((IsInst)inst.Left)); return LogicNot(IsType((IsInst)inst.Left));
} else if (inst.Right.OpCode == OpCode.IsInst && inst.Left.OpCode == OpCode.LdNull) { } else if (inst.Right.OpCode == OpCode.IsInst && inst.Left.OpCode == OpCode.LdNull) {
return LogicNot(IsType((IsInst)inst.Right)); return LogicNot(IsType((IsInst)inst.Right));
} }
var left = ConvertArgument(inst.Left); var left = ConvertArgument(inst.Left);
var right = ConvertArgument(inst.Right); var right = ConvertArgument(inst.Right);
return new ConvertedExpression( return new ConvertedExpression(
@ -262,6 +262,58 @@ namespace ICSharpCode.Decompiler.CSharp
left.Type); 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);
}
/// <summary>
/// Gets whether <paramref name="type"/> has the specified <paramref name="sign"/>.
/// If <paramref name="sign"/> is None, always returns true.
/// </summary>
bool IsCompatibleWithSign(IType type, Sign sign)
{
return sign == Sign.None || type.GetSign() == sign;
}
protected internal override ConvertedExpression VisitCall(Call inst) protected internal override ConvertedExpression VisitCall(Call inst)
{ {
return HandleCallInstruction(inst); return HandleCallInstruction(inst);

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -90,6 +90,7 @@
<Compile Include="IL\Instructions\SimpleInstruction.cs" /> <Compile Include="IL\Instructions\SimpleInstruction.cs" />
<Compile Include="IL\Instructions\TryInstruction.cs" /> <Compile Include="IL\Instructions\TryInstruction.cs" />
<Compile Include="IL\Instructions\UnaryInstruction.cs" /> <Compile Include="IL\Instructions\UnaryInstruction.cs" />
<Compile Include="IL\NRTypeExtensions.cs" />
<Compile Include="IL\TransformingVisitor.cs" /> <Compile Include="IL\TransformingVisitor.cs" />
<Compile Include="TypesHierarchyHelpers.cs" /> <Compile Include="TypesHierarchyHelpers.cs" />
<Compile Include="CecilExtensions.cs" /> <Compile Include="CecilExtensions.cs" />

106
ICSharpCode.Decompiler/IL/ILReader.cs

@ -188,11 +188,11 @@ namespace ICSharpCode.Decompiler.IL
switch (stack.PeekOrDefault()) { switch (stack.PeekOrDefault()) {
case StackType.I4: case StackType.I4:
case StackType.I: 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: 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: 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: default:
Warn("Unsupported input type for neg: "); Warn("Unsupported input type for neg: ");
goto case StackType.I4; goto case StackType.I4;
@ -216,9 +216,9 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Add: case ILOpCode.Add:
return BinaryNumeric(OpCode.Add); return BinaryNumeric(OpCode.Add);
case ILOpCode.Add_Ovf: case ILOpCode.Add_Ovf:
return BinaryNumeric(OpCode.Add, OverflowMode.Ovf); return BinaryNumeric(OpCode.Add, true, Sign.Signed);
case ILOpCode.Add_Ovf_Un: case ILOpCode.Add_Ovf_Un:
return BinaryNumeric(OpCode.Add, OverflowMode.Ovf_Un); return BinaryNumeric(OpCode.Add, true, Sign.Unsigned);
case ILOpCode.And: case ILOpCode.And:
return BinaryNumeric(OpCode.BitAnd); return BinaryNumeric(OpCode.BitAnd);
case ILOpCode.Arglist: case ILOpCode.Arglist:
@ -296,77 +296,77 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ckfinite: case ILOpCode.Ckfinite:
return new Ckfinite(); return new Ckfinite();
case ILOpCode.Conv_I1: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: case ILOpCode.Cpblk:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Div: case ILOpCode.Div:
return BinaryNumeric(OpCode.Div, OverflowMode.None); return BinaryNumeric(OpCode.Div, false, Sign.Signed);
case ILOpCode.Div_Un: case ILOpCode.Div_Un:
return BinaryNumeric(OpCode.Div, OverflowMode.Un); return BinaryNumeric(OpCode.Div, false, Sign.Unsigned);
case ILOpCode.Dup: case ILOpCode.Dup:
return new Peek(stack.Count > 0 ? stack.Peek() : StackType.Unknown); return new Peek(stack.Count > 0 ? stack.Peek() : StackType.Unknown);
case ILOpCode.Endfilter: case ILOpCode.Endfilter:
@ -458,11 +458,11 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Localloc: case ILOpCode.Localloc:
return new LocAlloc(Pop()); return new LocAlloc(Pop());
case ILOpCode.Mul: case ILOpCode.Mul:
return BinaryNumeric(OpCode.Mul, OverflowMode.None); return BinaryNumeric(OpCode.Mul, false, Sign.None);
case ILOpCode.Mul_Ovf: case ILOpCode.Mul_Ovf:
return BinaryNumeric(OpCode.Mul, OverflowMode.Ovf); return BinaryNumeric(OpCode.Mul, true, Sign.Signed);
case ILOpCode.Mul_Ovf_Un: case ILOpCode.Mul_Ovf_Un:
return BinaryNumeric(OpCode.Mul, OverflowMode.Ovf_Un); return BinaryNumeric(OpCode.Mul, true, Sign.Unsigned);
case ILOpCode.Neg: case ILOpCode.Neg:
return Neg(); return Neg();
case ILOpCode.Newobj: case ILOpCode.Newobj:
@ -476,17 +476,17 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Pop: case ILOpCode.Pop:
return new Void(Pop()); return new Void(Pop());
case ILOpCode.Rem: case ILOpCode.Rem:
return BinaryNumeric(OpCode.Rem, OverflowMode.None); return BinaryNumeric(OpCode.Rem, false, Sign.Signed);
case ILOpCode.Rem_Un: case ILOpCode.Rem_Un:
return BinaryNumeric(OpCode.Rem, OverflowMode.Un); return BinaryNumeric(OpCode.Rem, false, Sign.Unsigned);
case ILOpCode.Ret: case ILOpCode.Ret:
return Return(); return Return();
case ILOpCode.Shl: case ILOpCode.Shl:
return BinaryNumeric(OpCode.Shl, OverflowMode.None); return BinaryNumeric(OpCode.Shl, false, Sign.None);
case ILOpCode.Shr: case ILOpCode.Shr:
return BinaryNumeric(OpCode.Shr, OverflowMode.None); return BinaryNumeric(OpCode.Shr, false, Sign.Signed);
case ILOpCode.Shr_Un: case ILOpCode.Shr_Un:
return BinaryNumeric(OpCode.Shr, OverflowMode.Un); return BinaryNumeric(OpCode.Shr, 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:
@ -517,11 +517,11 @@ 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); return BinaryNumeric(OpCode.Sub, false, Sign.None);
case ILOpCode.Sub_Ovf: case ILOpCode.Sub_Ovf:
return BinaryNumeric(OpCode.Sub, OverflowMode.Ovf); return BinaryNumeric(OpCode.Sub, true, Sign.Signed);
case ILOpCode.Sub_Ovf_Un: case ILOpCode.Sub_Ovf_Un:
return BinaryNumeric(OpCode.Sub, OverflowMode.Ovf_Un); return BinaryNumeric(OpCode.Sub, true, Sign.Unsigned);
case ILOpCode.Switch: case ILOpCode.Switch:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Xor: 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 right = Pop();
var left = Pop(); var left = Pop();
return BinaryNumericInstruction.Create(opCode, left, right, overflowMode); return BinaryNumericInstruction.Create(opCode, left, right, checkForOverflow, sign);
} }
} }
} }

8
ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs

@ -40,13 +40,5 @@ namespace ICSharpCode.Decompiler.IL
{ {
output.Write(primitiveType.ToString().ToLowerInvariant()); 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");
}
} }
} }

42
ICSharpCode.Decompiler/IL/Instructions.cs

@ -393,7 +393,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Adds two numbers.</summary> /// <summary>Adds two numbers.</summary>
public sealed partial class Add : BinaryNumericInstruction 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
/// <summary>Subtracts two numbers</summary> /// <summary>Subtracts two numbers</summary>
public sealed partial class Sub : BinaryNumericInstruction 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
/// <summary>Multiplies two numbers</summary> /// <summary>Multiplies two numbers</summary>
public sealed partial class Mul : BinaryNumericInstruction 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
/// <summary>Divides two numbers</summary> /// <summary>Divides two numbers</summary>
public sealed partial class Div : BinaryNumericInstruction 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
/// <summary>Division remainder</summary> /// <summary>Division remainder</summary>
public sealed partial class Rem : BinaryNumericInstruction 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
/// <summary>Bitwise AND</summary> /// <summary>Bitwise AND</summary>
public sealed partial class BitAnd : BinaryNumericInstruction 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
/// <summary>Bitwise OR</summary> /// <summary>Bitwise OR</summary>
public sealed partial class BitOr : BinaryNumericInstruction 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
/// <summary>Bitwise XOR</summary> /// <summary>Bitwise XOR</summary>
public sealed partial class BitXor : BinaryNumericInstruction 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
/// <summary>Shift left</summary> /// <summary>Shift left</summary>
public sealed partial class Shl : BinaryNumericInstruction 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
/// <summary>Shift right</summary> /// <summary>Shift right</summary>
public sealed partial class Shr : BinaryNumericInstruction 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 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) { switch (opCode) {
case OpCode.Add: case OpCode.Add:
return new Add(left, right, overflowMode); return new Add(left, right, checkForOverflow, sign);
case OpCode.Sub: case OpCode.Sub:
return new Sub(left, right, overflowMode); return new Sub(left, right, checkForOverflow, sign);
case OpCode.Mul: case OpCode.Mul:
return new Mul(left, right, overflowMode); return new Mul(left, right, checkForOverflow, sign);
case OpCode.Div: case OpCode.Div:
return new Div(left, right, overflowMode); return new Div(left, right, checkForOverflow, sign);
case OpCode.Rem: case OpCode.Rem:
return new Rem(left, right, overflowMode); return new Rem(left, right, checkForOverflow, sign);
case OpCode.BitAnd: case OpCode.BitAnd:
return new BitAnd(left, right, overflowMode); return new BitAnd(left, right, checkForOverflow, sign);
case OpCode.BitOr: case OpCode.BitOr:
return new BitOr(left, right, overflowMode); return new BitOr(left, right, checkForOverflow, sign);
case OpCode.BitXor: case OpCode.BitXor:
return new BitXor(left, right, overflowMode); return new BitXor(left, right, checkForOverflow, sign);
case OpCode.Shl: case OpCode.Shl:
return new Shl(left, right, overflowMode); return new Shl(left, right, checkForOverflow, sign);
case OpCode.Shr: case OpCode.Shr:
return new Shr(left, right, overflowMode); return new Shr(left, right, checkForOverflow, sign);
default: default:
throw new ArgumentException("opCode is not a binary numeric instruction"); throw new ArgumentException("opCode is not a binary numeric instruction");
} }

13
ICSharpCode.Decompiler/IL/Instructions.tt

@ -248,12 +248,12 @@ namespace ICSharpCode.Decompiler.IL
partial class BinaryNumericInstruction 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) { switch (opCode) {
<# foreach (OpCode opCode in opCodes.Where(c => c.BaseClass == "BinaryNumericInstruction")) { #> <# foreach (OpCode opCode in opCodes.Where(c => c.BaseClass == "BinaryNumericInstruction")) { #>
case OpCode.<#=opCode.Name#>: case OpCode.<#=opCode.Name#>:
return new <#=opCode.Name#>(left, right, overflowMode); return new <#=opCode.Name#>(left, right, checkForOverflow, sign);
<# } #> <# } #>
default: default:
throw new ArgumentException("opCode is not a binary numeric instruction"); throw new ArgumentException("opCode is not a binary numeric instruction");
@ -477,9 +477,12 @@ namespace ICSharpCode.Decompiler.IL
static Action<OpCode> BinaryNumeric = opCode => { static Action<OpCode> BinaryNumeric = opCode => {
Binary(opCode); Binary(opCode);
opCode.BaseClass = "BinaryNumericInstruction"; opCode.BaseClass = "BinaryNumericInstruction";
opCode.ConstructorParameters.Add("OverflowMode overflowMode"); opCode.ConstructorParameters.Add("bool checkForOverflow");
opCode.BaseConstructorArguments.Add("overflowMode"); opCode.BaseConstructorArguments.Add("checkForOverflow");
opCode.WriteOpCodeSuffix.Add("output.WriteSuffix(overflowMode);"); 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. // BinaryNumeric trait: the instruction is derived from BinaryComparisonInstruction. Implies Binary and I4Result.

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

@ -24,29 +24,27 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
[Flags]
public enum OverflowMode : byte
{
/// <summary>Don't check for overflow, treat integers as signed.</summary>
None = 0,
/// <summary>Check for overflow, treat integers as signed.</summary>
Ovf = 1,
/// <summary>Don't check for overflow, treat integers as unsigned.</summary>
Un = 2,
/// <summary>Check for overflow, treat integers as unsigned.</summary>
Ovf_Un = 3
}
public abstract partial class BinaryNumericInstruction : BinaryInstruction public abstract partial class BinaryNumericInstruction : BinaryInstruction
{ {
public readonly OverflowMode OverflowMode; /// <summary>
/// Gets whether the instruction checks for overflow.
/// </summary>
public readonly bool CheckForOverflow;
/// <summary>
/// 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.
/// </summary>
public readonly Sign Sign;
readonly StackType resultType; 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) : base(opCode, left, right)
{ {
this.OverflowMode = overflowMode; this.CheckForOverflow = checkForOverflow;
this.Sign = sign;
this.resultType = ComputeResultType(opCode, left.ResultType, right.ResultType); this.resultType = ComputeResultType(opCode, left.ResultType, right.ResultType);
} }
@ -83,7 +81,7 @@ namespace ICSharpCode.Decompiler.IL
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
var flags = base.ComputeFlags(); var flags = base.ComputeFlags();
if ((OverflowMode & OverflowMode.Ovf) != 0) if (CheckForOverflow)
flags |= InstructionFlags.MayThrow; flags |= InstructionFlags.MayThrow;
return flags; return flags;
} }
@ -91,7 +89,12 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.Write(OpCode); 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('('); output.Write('(');
Left.WriteTo(output); Left.WriteTo(output);
output.Write(", "); output.Write(", ");

21
ICSharpCode.Decompiler/IL/Instructions/Conv.cs

@ -23,12 +23,18 @@ namespace ICSharpCode.Decompiler.IL
partial class Conv : UnaryInstruction partial class Conv : UnaryInstruction
{ {
public readonly PrimitiveType TargetType; public readonly PrimitiveType TargetType;
public readonly OverflowMode ConvMode; public readonly bool CheckForOverflow;
public Conv(ILInstruction argument, PrimitiveType targetType, OverflowMode convMode) : base(OpCode.Conv, argument) /// <summary>
/// Gets the sign of the input type.
/// </summary>
public readonly Sign Sign;
public Conv(ILInstruction argument, PrimitiveType targetType, bool checkForOverflow, Sign sign) : base(OpCode.Conv, argument)
{ {
this.TargetType = targetType; this.TargetType = targetType;
this.ConvMode = convMode; this.CheckForOverflow = checkForOverflow;
this.Sign = sign;
} }
public override StackType ResultType { public override StackType ResultType {
@ -38,7 +44,12 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.Write(OpCode); 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(' ');
output.Write(Argument.ResultType); output.Write(Argument.ResultType);
output.Write("->"); output.Write("->");
@ -51,7 +62,7 @@ namespace ICSharpCode.Decompiler.IL
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
var flags = base.ComputeFlags(); var flags = base.ComputeFlags();
if ((ConvMode & OverflowMode.Ovf) != 0) if (CheckForOverflow)
flags |= InstructionFlags.MayThrow; flags |= InstructionFlags.MayThrow;
return flags; return flags;
} }

125
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
}
}

2
ICSharpCode.Decompiler/IL/StackType.cs

@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.IL
I4, I4,
/// <summary>64-bit integer</summary> /// <summary>64-bit integer</summary>
I8, I8,
/// <summary>native-size integer</summary> /// <summary>native-size integer, or unmanaged pointer</summary>
I, I,
/// <summary>Floating point number</summary> /// <summary>Floating point number</summary>
F, F,

4
ILSpy/Properties/AssemblyInfo.template.cs

@ -31,8 +31,8 @@ using System.Runtime.InteropServices;
internal static class RevisionClass internal static class RevisionClass
{ {
public const string Major = "2"; public const string Major = "3";
public const string Minor = "1"; public const string Minor = "0";
public const string Build = "0"; public const string Build = "0";
public const string Revision = "$INSERTREVISION$"; public const string Revision = "$INSERTREVISION$";
public const string VersionName = null; public const string VersionName = null;

Loading…
Cancel
Save