|
|
|
@ -128,7 +128,7 @@ namespace ICSharpCode.Decompiler.IL |
|
|
|
/// Gets whether the instruction checks for overflow.
|
|
|
|
/// Gets whether the instruction checks for overflow.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
public readonly bool CheckForOverflow; |
|
|
|
public readonly bool CheckForOverflow; |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// For integer operations that depend on the sign, specifies whether the operation
|
|
|
|
/// For integer operations that depend on the sign, specifies whether the operation
|
|
|
|
/// is signed or unsigned.
|
|
|
|
/// is signed or unsigned.
|
|
|
|
@ -151,7 +151,7 @@ namespace ICSharpCode.Decompiler.IL |
|
|
|
CompoundTargetKind targetKind, ILInstruction value, IType type, CompoundEvalMode evalMode) |
|
|
|
CompoundTargetKind targetKind, ILInstruction value, IType type, CompoundEvalMode evalMode) |
|
|
|
: base(OpCode.NumericCompoundAssign, evalMode, target, targetKind, value) |
|
|
|
: base(OpCode.NumericCompoundAssign, evalMode, target, targetKind, value) |
|
|
|
{ |
|
|
|
{ |
|
|
|
Debug.Assert(IsBinaryCompatibleWithType(binary, type)); |
|
|
|
Debug.Assert(IsBinaryCompatibleWithType(binary, type, null)); |
|
|
|
this.CheckForOverflow = binary.CheckForOverflow; |
|
|
|
this.CheckForOverflow = binary.CheckForOverflow; |
|
|
|
this.Sign = binary.Sign; |
|
|
|
this.Sign = binary.Sign; |
|
|
|
this.LeftInputType = binary.LeftInputType; |
|
|
|
this.LeftInputType = binary.LeftInputType; |
|
|
|
@ -164,11 +164,11 @@ namespace ICSharpCode.Decompiler.IL |
|
|
|
Debug.Assert(evalMode == CompoundEvalMode.EvaluatesToNewValue || (Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub)); |
|
|
|
Debug.Assert(evalMode == CompoundEvalMode.EvaluatesToNewValue || (Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub)); |
|
|
|
Debug.Assert(this.ResultType == (IsLifted ? StackType.O : UnderlyingResultType)); |
|
|
|
Debug.Assert(this.ResultType == (IsLifted ? StackType.O : UnderlyingResultType)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Gets whether the specific binary instruction is compatible with a compound operation on the specified type.
|
|
|
|
/// Gets whether the specific binary instruction is compatible with a compound operation on the specified type.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type) |
|
|
|
internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type, DecompilerSettings settings) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (binary.IsLifted) { |
|
|
|
if (binary.IsLifted) { |
|
|
|
if (!NullableType.IsNullable(type)) |
|
|
|
if (!NullableType.IsNullable(type)) |
|
|
|
@ -201,6 +201,19 @@ namespace ICSharpCode.Decompiler.IL |
|
|
|
default: |
|
|
|
default: |
|
|
|
return false; // operator not supported on pointer types
|
|
|
|
return false; // operator not supported on pointer types
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else if (type.IsKnownType(KnownTypeCode.IntPtr) || type.IsKnownType(KnownTypeCode.UIntPtr)) { |
|
|
|
|
|
|
|
// "target.intptr *= 2;" is compiler error, but
|
|
|
|
|
|
|
|
// "target.intptr *= (nint)2;" works
|
|
|
|
|
|
|
|
if (settings != null && !settings.NativeIntegers) { |
|
|
|
|
|
|
|
// But if native integers are not available, we cannot use compound assignment.
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// The trick with casting the RHS to n(u)int doesn't work for shifts:
|
|
|
|
|
|
|
|
switch (binary.Operator) { |
|
|
|
|
|
|
|
case BinaryNumericOperator.ShiftLeft: |
|
|
|
|
|
|
|
case BinaryNumericOperator.ShiftRight: |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (binary.Sign != Sign.None) { |
|
|
|
if (binary.Sign != Sign.None) { |
|
|
|
if (type.IsCSharpSmallIntegerType()) { |
|
|
|
if (type.IsCSharpSmallIntegerType()) { |
|
|
|
|