Browse Source

Add DetectImprovedTypeForForBitOp as a transform step.

Previously this happened within the InferType implementation.
pull/4090/head
Daniel Grunwald 2 weeks ago
parent
commit
76f67f3fca
  1. 12
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  2. 31
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

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

@ -78,6 +78,14 @@ namespace ICSharpCode.Decompiler.IL
readonly StackType resultType; readonly StackType resultType;
/// <summary>
/// Result type of this instruction. If not null, InferType() will return this type.
/// Can be used to store an improved C# type for the result of this instruction,
/// e.g. `bit.or.i4(bool1, bool2)` can use CSharpResultType = bool after the
/// ExpressionTransform has determined that the result is always 0 or 1.
/// </summary>
public IType? CSharpResultType { get; set; }
public BinaryNumericInstruction(BinaryNumericOperator op, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) public BinaryNumericInstruction(BinaryNumericOperator op, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign)
: this(op, left, right, left.ResultType, right.ResultType, checkForOverflow, sign) : this(op, left, right, left.ResultType, right.ResultType, checkForOverflow, sign)
{ {
@ -123,7 +131,7 @@ namespace ICSharpCode.Decompiler.IL
return StackType.Unknown; return StackType.Unknown;
} }
public StackType UnderlyingResultType { get => resultType; } public StackType UnderlyingResultType => resultType;
public sealed override StackType ResultType { public sealed override StackType ResultType {
get => IsLifted ? StackType.O : resultType; get => IsLifted ? StackType.O : resultType;
@ -131,6 +139,8 @@ namespace ICSharpCode.Decompiler.IL
public override IType InferType(ICompilation compilation) public override IType InferType(ICompilation compilation)
{ {
if (CSharpResultType != null)
return CSharpResultType;
IType type = compilation.FindType(UnderlyingResultType); IType type = compilation.FindType(UnderlyingResultType);
if (IsLifted) if (IsLifted)
return NullableType.Create(compilation, type); return NullableType.Create(compilation, type);

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

@ -863,8 +863,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
break; break;
case BinaryNumericOperator.BitAnd: case BinaryNumericOperator.BitAnd:
if (inst.Left.InferType(context.TypeSystem).IsKnownType(KnownTypeCode.Boolean) {
&& inst.Right.InferType(context.TypeSystem).IsKnownType(KnownTypeCode.Boolean)) IType leftType = inst.Left.InferType(context.TypeSystem);
IType rightType = inst.Right.InferType(context.TypeSystem);
DetectImprovedTypeForForBitOp(inst, leftType, rightType);
if (leftType.IsKnownType(KnownTypeCode.Boolean)
&& rightType.IsKnownType(KnownTypeCode.Boolean))
{ {
if (new NullableLiftingTransform(context).Run(inst)) if (new NullableLiftingTransform(context).Run(inst))
{ {
@ -872,6 +876,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
} }
break; break;
}
case BinaryNumericOperator.BitOr:
case BinaryNumericOperator.BitXor:
{
IType leftType = inst.Left.InferType(context.TypeSystem);
IType rightType = inst.Right.InferType(context.TypeSystem);
DetectImprovedTypeForForBitOp(inst, leftType, rightType);
break;
}
} }
bool MatchExpectedShiftSize(ILInstruction rhs) bool MatchExpectedShiftSize(ILInstruction rhs)
@ -894,6 +907,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
} }
// Given bit.or(a, b), promotes the "known to be bool/short" information from the operands to bit.or
void DetectImprovedTypeForForBitOp(BinaryNumericInstruction inst, IType leftType, IType rightType)
{
if (leftType.Equals(rightType) && (leftType.IsCSharpPrimitiveIntegerType() || leftType.IsCSharpNativeIntegerType() || leftType.IsKnownType(KnownTypeCode.Boolean)))
{
if (!leftType.Equals(inst.CSharpResultType))
{
context.Step("DetectImprovedTypeForForBitOp", inst);
inst.CSharpResultType = leftType;
context.EndStep(inst);
}
}
}
protected internal override void VisitTryCatchHandler(TryCatchHandler inst) protected internal override void VisitTryCatchHandler(TryCatchHandler inst)
{ {
base.VisitTryCatchHandler(inst); base.VisitTryCatchHandler(inst);

Loading…
Cancel
Save