Browse Source

[nullables] Add lifting for operator~.

pull/870/head
Daniel Grunwald 8 years ago
parent
commit
63d6f4bbca
  1. 35
      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

35
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -345,33 +345,30 @@ namespace ICSharpCode.Decompiler.CSharp @@ -345,33 +345,30 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitBitNot(BitNot inst, TranslationContext context)
{
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)
// -> we need to perform sign/zero-extension before the BitNot.
// 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).
argument = argument.ConvertTo(compilation.FindType(inst.ResultType.ToKnownTypeCode(argument.Type.GetSign())), this);
}
var type = argument.Type.GetDefinition();
if (type != null) {
// Handle those types that don't support operator ~
// Same if the type is one that does not support ~ (IntPtr, bool and char).
StackType targetStackType = inst.UnderlyingResultType;
if (targetStackType == StackType.I) {
// IntPtr doesn't support operator ~.
// Note that it's OK to use a type that's larger than necessary.
switch (type.KnownTypeCode) {
case KnownTypeCode.Boolean:
case KnownTypeCode.Char:
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;
targetStackType = StackType.I8;
}
IType targetType = compilation.FindType(targetStackType.ToKnownTypeCode(argUType.GetSign()));
if (inst.IsLifted) {
targetType = NullableType.Create(compilation, targetType);
}
argument = argument.ConvertTo(targetType, this);
}
return new UnaryOperatorExpression(UnaryOperatorType.BitNot, argument)

15
ICSharpCode.Decompiler/IL/Instructions.cs

@ -952,9 +952,6 @@ namespace ICSharpCode.Decompiler.IL @@ -952,9 +952,6 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Bitwise NOT</summary>
public sealed partial class BitNot : UnaryInstruction
{
public BitNot(ILInstruction argument) : base(OpCode.BitNot, argument)
{
}
public override void AcceptVisitor(ILVisitor visitor)
{
@ -971,7 +968,7 @@ namespace ICSharpCode.Decompiler.IL @@ -971,7 +968,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
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 @@ -5092,16 +5089,6 @@ namespace ICSharpCode.Decompiler.IL
body = default(ILInstruction);
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()
{
var inst = this as Arglist;

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -70,7 +70,7 @@ @@ -70,7 +70,7 @@
CustomClassName("CompoundAssignmentInstruction"), CustomConstructor, CustomComputeFlags,
MayThrow, CustomArguments("target", "value"), HasTypeOperand, ResultType("type.GetStackType()"), CustomWriteTo,
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("br", "Unconditional branch. <c>goto target;</c>",
CustomClassName("Branch"), NoArguments, CustomConstructor, UnconditionalBranch, MayBranch, CustomComputeFlags,

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

@ -16,15 +16,37 @@ @@ -16,15 +16,37 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Diagnostics;
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 {
get {
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 @@ -370,6 +370,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
};
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) {
var (left, leftBits) = DoLift(binary.Left);
var (right, rightBits) = DoLift(binary.Right);

Loading…
Cancel
Save