Browse Source

[nullables] Add lifting for operator~.

pull/870/head
Daniel Grunwald 8 years ago
parent
commit
63d6f4bbca
  1. 39
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 15
      ICSharpCode.Decompiler/IL/Instructions.cs
  3. 2
      ICSharpCode.Decompiler/IL/Instructions.tt
  4. 24
      ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs
  5. 8
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

39
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -345,33 +345,30 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitBitNot(BitNot inst, TranslationContext context) protected internal override TranslatedExpression VisitBitNot(BitNot inst, TranslationContext context)
{ {
var argument = Translate(inst.Argument); var argument = Translate(inst.Argument);
var argUType = NullableType.GetUnderlyingType(argument.Type);
if (argument.Type.GetStackType().GetSize() < inst.ResultType.GetSize()
|| argument.Type.Kind == TypeKind.Enum && argument.Type.IsSmallIntegerType()) if (argUType.GetStackType().GetSize() < inst.UnderlyingResultType.GetSize()
|| argUType.Kind == TypeKind.Enum && argUType.IsSmallIntegerType()
|| argUType.GetStackType() == StackType.I
|| argUType.IsKnownType(KnownTypeCode.Boolean)
|| argUType.IsKnownType(KnownTypeCode.Char))
{ {
// Argument is undersized (even after implicit integral promotion to I4) // Argument is undersized (even after implicit integral promotion to I4)
// -> we need to perform sign/zero-extension before the BitNot. // -> we need to perform sign/zero-extension before the BitNot.
// Same if the argument is an enum based on a small integer type // Same if the argument is an enum based on a small integer type
// (those don't undergo numeric promotion in C# the way non-enum small integer types do). // (those don't undergo numeric promotion in C# the way non-enum small integer types do).
argument = argument.ConvertTo(compilation.FindType(inst.ResultType.ToKnownTypeCode(argument.Type.GetSign())), this); // Same if the type is one that does not support ~ (IntPtr, bool and char).
} StackType targetStackType = inst.UnderlyingResultType;
if (targetStackType == StackType.I) {
var type = argument.Type.GetDefinition(); // IntPtr doesn't support operator ~.
if (type != null) { // Note that it's OK to use a type that's larger than necessary.
// Handle those types that don't support operator ~ targetStackType = StackType.I8;
// Note that it's OK to use a type that's larger than necessary. }
switch (type.KnownTypeCode) { IType targetType = compilation.FindType(targetStackType.ToKnownTypeCode(argUType.GetSign()));
case KnownTypeCode.Boolean: if (inst.IsLifted) {
case KnownTypeCode.Char: targetType = NullableType.Create(compilation, targetType);
argument = argument.ConvertTo(compilation.FindType(KnownTypeCode.UInt32), this);
break;
case KnownTypeCode.IntPtr:
argument = argument.ConvertTo(compilation.FindType(KnownTypeCode.Int64), this);
break;
case KnownTypeCode.UIntPtr:
argument = argument.ConvertTo(compilation.FindType(KnownTypeCode.UInt64), this);
break;
} }
argument = argument.ConvertTo(targetType, this);
} }
return new UnaryOperatorExpression(UnaryOperatorType.BitNot, argument) return new UnaryOperatorExpression(UnaryOperatorType.BitNot, argument)

15
ICSharpCode.Decompiler/IL/Instructions.cs

@ -952,9 +952,6 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise NOT</summary> /// <summary>Bitwise NOT</summary>
public sealed partial class BitNot : UnaryInstruction public sealed partial class BitNot : UnaryInstruction
{ {
public BitNot(ILInstruction argument) : base(OpCode.BitNot, argument)
{
}
public override void AcceptVisitor(ILVisitor visitor) public override void AcceptVisitor(ILVisitor visitor)
{ {
@ -971,7 +968,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{ {
var o = other as BitNot; var o = other as BitNot;
return o != null && this.Argument.PerformMatch(o.Argument, ref match); return o != null && this.Argument.PerformMatch(o.Argument, ref match) && IsLifted == o.IsLifted && UnderlyingResultType == o.UnderlyingResultType;
} }
} }
} }
@ -5092,16 +5089,6 @@ namespace ICSharpCode.Decompiler.IL
body = default(ILInstruction); body = default(ILInstruction);
return false; return false;
} }
public bool MatchBitNot(out ILInstruction argument)
{
var inst = this as BitNot;
if (inst != null) {
argument = inst.Argument;
return true;
}
argument = default(ILInstruction);
return false;
}
public bool MatchArglist() public bool MatchArglist()
{ {
var inst = this as Arglist; var inst = this as Arglist;

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -70,7 +70,7 @@
CustomClassName("CompoundAssignmentInstruction"), CustomConstructor, CustomComputeFlags, CustomClassName("CompoundAssignmentInstruction"), CustomConstructor, CustomComputeFlags,
MayThrow, CustomArguments("target", "value"), HasTypeOperand, ResultType("type.GetStackType()"), CustomWriteTo, MayThrow, CustomArguments("target", "value"), HasTypeOperand, ResultType("type.GetStackType()"), CustomWriteTo,
MatchCondition("CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator")), MatchCondition("CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator")),
new OpCode("bit.not", "Bitwise NOT", Unary), new OpCode("bit.not", "Bitwise NOT", Unary, CustomConstructor, MatchCondition("IsLifted == o.IsLifted && UnderlyingResultType == o.UnderlyingResultType")),
new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")), new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
new OpCode("br", "Unconditional branch. <c>goto target;</c>", new OpCode("br", "Unconditional branch. <c>goto target;</c>",
CustomClassName("Branch"), NoArguments, CustomConstructor, UnconditionalBranch, MayBranch, CustomComputeFlags, CustomClassName("Branch"), NoArguments, CustomConstructor, UnconditionalBranch, MayBranch, CustomComputeFlags,

24
ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs

@ -16,15 +16,37 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System.Diagnostics;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
partial class BitNot partial class BitNot : ILiftableInstruction
{ {
public BitNot(ILInstruction arg) : base(OpCode.BitNot, arg)
{
this.UnderlyingResultType = arg.ResultType;
}
public BitNot(ILInstruction arg, bool isLifted, StackType stackType) : base(OpCode.BitNot, arg)
{
this.IsLifted = isLifted;
this.UnderlyingResultType = stackType;
}
public bool IsLifted { get; }
public StackType UnderlyingResultType { get; }
public override StackType ResultType { public override StackType ResultType {
get { get {
return Argument.ResultType; return Argument.ResultType;
} }
} }
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(IsLifted == (ResultType == StackType.O));
Debug.Assert(IsLifted || ResultType == UnderlyingResultType);
}
} }
} }

8
ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

@ -370,6 +370,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}; };
return (newInst, bits); return (newInst, bits);
} }
} else if (inst is BitNot bitnot) {
var (arg, bits) = DoLift(bitnot.Argument);
if (arg != null) {
var newInst = new BitNot(arg, isLifted: true, stackType: bitnot.ResultType) {
ILRange = bitnot.ILRange
};
return (newInst, bits);
}
} else if (inst is BinaryNumericInstruction binary) { } else if (inst is BinaryNumericInstruction binary) {
var (left, leftBits) = DoLift(binary.Left); var (left, leftBits) = DoLift(binary.Left);
var (right, rightBits) = DoLift(binary.Right); var (right, rightBits) = DoLift(binary.Right);

Loading…
Cancel
Save