Browse Source

Avoid unnecessary casts for bitshifts.

pull/863/head
Daniel Grunwald 8 years ago
parent
commit
9e38bcea5f
  1. 33
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 17
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

33
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -648,29 +648,40 @@ namespace ICSharpCode.Decompiler.CSharp
return true; return true;
} }
} }
TranslatedExpression HandleShift(BinaryNumericInstruction inst, BinaryOperatorType op) TranslatedExpression HandleShift(BinaryNumericInstruction inst, BinaryOperatorType op)
{ {
var left = Translate(inst.Left); var left = Translate(inst.Left);
var right = Translate(inst.Right); var right = Translate(inst.Right);
IType targetType; Sign sign = inst.Sign;
if (inst.ResultType == StackType.I4) if (left.Type.IsSmallIntegerType() && sign != Sign.Unsigned
targetType = compilation.FindType(inst.Sign == Sign.Unsigned ? KnownTypeCode.UInt32 : KnownTypeCode.Int32); && left.Type.Kind != TypeKind.Enum && inst.ResultType == StackType.I4) {
else // With small integer types, C# will promote to int and perform signed shifts.
targetType = compilation.FindType(inst.Sign == Sign.Unsigned ? KnownTypeCode.UInt64 : KnownTypeCode.Int64); // We thus don't need any casts in this case.
left = left.ConvertTo(targetType, this); } else {
// Insert cast to target type.
if (sign == Sign.None) {
// if we don't need a specific sign, prefer keeping that of the input:
sign = left.Type.GetSign();
}
IType targetType;
if (inst.ResultType == StackType.I4)
targetType = compilation.FindType(sign == Sign.Unsigned ? KnownTypeCode.UInt32 : KnownTypeCode.Int32);
else
targetType = compilation.FindType(sign == Sign.Unsigned ? KnownTypeCode.UInt64 : KnownTypeCode.Int64);
left = left.ConvertTo(targetType, this);
}
// Shift operators in C# always expect type 'int' on the right-hand-side // Shift operators in C# always expect type 'int' on the right-hand-side
right = right.ConvertTo(compilation.FindType(KnownTypeCode.Int32), this); right = right.ConvertTo(compilation.FindType(KnownTypeCode.Int32), this);
TranslatedExpression result = new BinaryOperatorExpression(left.Expression, op, right.Expression) TranslatedExpression result = new BinaryOperatorExpression(left.Expression, op, right.Expression)
.WithILInstruction(inst) .WithILInstruction(inst)
.WithRR(resolver.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult)); .WithRR(resolver.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult));
if (inst.ResultType == StackType.I) { if (inst.ResultType == StackType.I) {
// C# doesn't have shift operators for IntPtr, so we first shifted a long/ulong, // C# doesn't have shift operators for IntPtr, so we first shifted a long/ulong,
// and now have to case back down to IntPtr/UIntPtr: // and now have to case back down to IntPtr/UIntPtr:
result = result.ConvertTo(compilation.FindType(inst.Sign == Sign.Unsigned ? KnownTypeCode.UIntPtr : KnownTypeCode.IntPtr), this); result = result.ConvertTo(compilation.FindType(sign == Sign.Unsigned ? KnownTypeCode.UIntPtr : KnownTypeCode.IntPtr), this);
} }
return result; return result;
} }

17
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -277,5 +277,22 @@ namespace ICSharpCode.Decompiler.IL.Transforms
inst.ReplaceWith(new StLoc(v, new IfInstruction(new LogicNot(inst.Condition), value2, value1))); inst.ReplaceWith(new StLoc(v, new IfInstruction(new LogicNot(inst.Condition), value2, value1)));
} }
} }
protected internal override void VisitBinaryNumericInstruction(BinaryNumericInstruction inst)
{
base.VisitBinaryNumericInstruction(inst);
switch (inst.Operator) {
case BinaryNumericOperator.ShiftLeft:
case BinaryNumericOperator.ShiftRight:
if (inst.Right.MatchBinaryNumericInstruction(BinaryNumericOperator.BitAnd, out var lhs, out var rhs)
&& rhs.MatchLdcI4(inst.ResultType == StackType.I8 ? 63 : 31))
{
// a << (b & 31) => a << b
context.Step("Combine bit.and into shift", inst);
inst.Right = lhs;
}
break;
}
}
} }
} }

Loading…
Cancel
Save