Browse Source

Handle Comp in InferType().

pull/1305/head
Daniel Grunwald 7 years ago
parent
commit
12e74daf48
  1. 16
      ICSharpCode.Decompiler/IL/ILTypeExtensions.cs
  2. 2
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  3. 21
      ICSharpCode.Decompiler/IL/SemanticHelper.cs
  4. 2
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  5. 10
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  6. 2
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
  7. 2
      ICSharpCode.Decompiler/IL/Transforms/RemoveDeadVariableInit.cs
  8. 34
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
  9. 2
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

16
ICSharpCode.Decompiler/IL/ILTypeExtensions.cs

@ -131,7 +131,7 @@ namespace ICSharpCode.Decompiler.IL @@ -131,7 +131,7 @@ namespace ICSharpCode.Decompiler.IL
///
/// Returns SpecialType.UnknownType for unsupported instructions.
/// </summary>
public static IType InferType(this ILInstruction inst)
public static IType InferType(this ILInstruction inst, ICompilation compilation)
{
switch (inst) {
case NewObj newObj:
@ -159,12 +159,24 @@ namespace ICSharpCode.Decompiler.IL @@ -159,12 +159,24 @@ namespace ICSharpCode.Decompiler.IL
case LdsFlda ldsflda:
return new ByReferenceType(ldsflda.Field.Type);
case LdElema ldelema:
if (ldelema.Array.InferType() is ArrayType arrayType) {
if (ldelema.Array.InferType(compilation) is ArrayType arrayType) {
if (TypeUtils.IsCompatibleTypeForMemoryAccess(arrayType.ElementType, ldelema.Type)) {
return new ByReferenceType(arrayType.ElementType);
}
}
return new ByReferenceType(ldelema.Type);
case Comp comp:
if (compilation == null)
return SpecialType.UnknownType;
switch (comp.LiftingKind) {
case ComparisonLiftingKind.None:
case ComparisonLiftingKind.CSharp:
return compilation.FindType(KnownTypeCode.Boolean);
case ComparisonLiftingKind.ThreeValuedLogic:
return NullableType.Create(compilation, compilation.FindType(KnownTypeCode.Boolean));
default:
return SpecialType.UnknownType;
}
default:
return SpecialType.UnknownType;
}

2
ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs

@ -148,7 +148,7 @@ namespace ICSharpCode.Decompiler.IL @@ -148,7 +148,7 @@ namespace ICSharpCode.Decompiler.IL
}
}
// Can't transform if the RHS value would be need to be truncated for the LHS type.
if (Transforms.TransformAssignment.IsImplicitTruncation(binary.Right, type, binary.IsLifted))
if (Transforms.TransformAssignment.IsImplicitTruncation(binary.Right, type, null, binary.IsLifted))
return false;
return true;
}

21
ICSharpCode.Decompiler/IL/SemanticHelper.cs

@ -44,27 +44,6 @@ namespace ICSharpCode.Decompiler.IL @@ -44,27 +44,6 @@ namespace ICSharpCode.Decompiler.IL
return (inst & ~pureFlags) == 0;
}
/// <summary>
/// Gets whether the instruction sequence 'inst1; inst2;' may be ordered to 'inst2; inst1;'
/// </summary>
internal static bool MayReorder(InstructionFlags inst1, InstructionFlags inst2)
{
// If both instructions perform an impure action, we cannot reorder them
if (!IsPure(inst1) && !IsPure(inst2))
return false;
// We cannot reorder if inst2 might write what inst1 looks at
if (ConflictingPair(inst1, inst2, InstructionFlags.MayReadLocals, InstructionFlags.MayWriteLocals | InstructionFlags.SideEffect))
return false;
return true;
}
private static bool ConflictingPair(InstructionFlags inst1, InstructionFlags inst2, InstructionFlags readFlag, InstructionFlags writeFlag)
{
// if one instruction has the read flag and the other the write flag, that's a conflict
return (inst1 & readFlag) != 0 && (inst2 & writeFlag) != 0
|| (inst2 & readFlag) != 0 && (inst1 & writeFlag) != 0;
}
/// <summary>
/// Gets whether the instruction sequence 'inst1; inst2;' may be ordered to 'inst2; inst1;'
/// </summary>

2
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -448,7 +448,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -448,7 +448,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!variableType.IsKnownType(KnownTypeCode.Object))
return variableType;
IType inferredType = inst.InferType();
IType inferredType = inst.InferType(context.TypeSystem);
if (inferredType.Kind != TypeKind.Unknown)
return inferredType;
else

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

@ -498,7 +498,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -498,7 +498,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
break;
case BinaryNumericOperator.BitAnd:
if (IsBoolean(inst.Left) && IsBoolean(inst.Right) && SemanticHelper.IsPure(inst.Right.Flags))
if (inst.Left.InferType(context.TypeSystem).IsKnownType(KnownTypeCode.Boolean)
&& inst.Right.InferType(context.TypeSystem).IsKnownType(KnownTypeCode.Boolean)
&& SemanticHelper.IsPure(inst.Right.Flags))
{
context.Step("Replace bit.and with logic.and", inst);
var expr = IfInstruction.LogicAnd(inst.Left, inst.Right);
@ -508,11 +510,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -508,11 +510,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
break;
}
}
private static bool IsBoolean(ILInstruction inst) =>
inst is Comp c && c.ResultType == StackType.I4 ||
inst.InferType().IsKnownType(KnownTypeCode.Boolean);
protected internal override void VisitTryCatchHandler(TryCatchHandler inst)
{
base.VisitTryCatchHandler(inst);

2
ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

@ -111,7 +111,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -111,7 +111,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!IsValidAccessChain(testedVar, mode, nonNullInst, out var varLoad))
return null;
// note: InferType will be accurate in this case because the access chain consists of calls and field accesses
IType returnType = nonNullInst.InferType();
IType returnType = nonNullInst.InferType(context.TypeSystem);
if (nullInst.MatchLdNull()) {
context.Step($"Null propagation (mode={mode}, output=reference type)", nonNullInst);
// testedVar != null ? testedVar.AccessChain : null

2
ICSharpCode.Decompiler/IL/Transforms/RemoveDeadVariableInit.cs

@ -76,7 +76,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -76,7 +76,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
IType newType = null;
// Multiple store are possible in case of (c ? ref a : ref b) += 1, for example.
foreach (var stloc in v.StoreInstructions.OfType<StLoc>()) {
var inferredType = stloc.Value.InferType();
var inferredType = stloc.Value.InferType(context.TypeSystem);
// cancel, if types of values do not match exactly
if (newType != null && !newType.Equals(inferredType)) {
newType = SpecialType.UnknownType;

34
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -88,7 +88,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -88,7 +88,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// in some cases it can be a compiler-generated local
if (inst == null || (inst.Variable.Kind != VariableKind.StackSlot && inst.Variable.Kind != VariableKind.Local))
return false;
if (IsImplicitTruncation(inst.Value, inst.Variable.Type)) {
if (IsImplicitTruncation(inst.Value, inst.Variable.Type, context.TypeSystem)) {
// 'stloc s' is implicitly truncating the value
return false;
}
@ -112,7 +112,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -112,7 +112,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!SemanticHelper.IsPure(stobj.Target.Flags) || inst.Variable.IsUsedWithin(stobj.Target))
return false;
var pointerType = stobj.Target.InferType();
var pointerType = stobj.Target.InferType(context.TypeSystem);
IType newType = stobj.Type;
if (TypeUtils.IsCompatiblePointerTypeForMemoryAccess(pointerType, stobj.Type)) {
if (pointerType is ByReferenceType byref)
@ -120,7 +120,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -120,7 +120,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
else if (pointerType is PointerType pointer)
newType = pointer.ElementType;
}
if (IsImplicitTruncation(inst.Value, newType)) {
if (IsImplicitTruncation(inst.Value, newType, context.TypeSystem)) {
// 'stobj' is implicitly truncating the value
return false;
}
@ -146,7 +146,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -146,7 +146,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!SemanticHelper.IsPure(arg.Flags) || inst.Variable.IsUsedWithin(arg))
return false;
}
if (IsImplicitTruncation(inst.Value, call.Method.Parameters.Last().Type)) {
if (IsImplicitTruncation(inst.Value, call.Method.Parameters.Last().Type, context.TypeSystem)) {
// setter call is implicitly truncating the value
return false;
}
@ -242,7 +242,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -242,7 +242,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// changes the return value of the expression, so this is only valid on block-level.
return false;
}
if (!IsCompoundStore(compoundStore, out var targetType, out var setterValue))
if (!IsCompoundStore(compoundStore, out var targetType, out var setterValue, context.TypeSystem))
return false;
// targetType = The type of the property/field/etc. being stored to.
// setterValue = The value being stored.
@ -342,11 +342,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -342,11 +342,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!nextInst.Value.MatchLdLoc(inst.Variable))
return false;
if (IsImplicitTruncation(inst.Value, inst.Variable.Type)) {
if (IsImplicitTruncation(inst.Value, inst.Variable.Type, context.TypeSystem)) {
// 'stloc s' is implicitly truncating the stack value
return false;
}
if (IsImplicitTruncation(inst.Value, nextInst.Variable.Type)) {
if (IsImplicitTruncation(inst.Value, nextInst.Variable.Type, context.TypeSystem)) {
// 'stloc l' is implicitly truncating the stack value
return false;
}
@ -371,7 +371,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -371,7 +371,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Gets whether 'stobj type(..., value)' would evaluate to a different value than 'value'
/// due to implicit truncation.
/// </summary>
static internal bool IsImplicitTruncation(ILInstruction value, IType type, bool allowNullableValue = false)
static internal bool IsImplicitTruncation(ILInstruction value, IType type, ICompilation compilation, bool allowNullableValue = false)
{
if (!type.IsSmallIntegerType()) {
// Implicit truncation in ILAst only happens for small integer types;
@ -401,10 +401,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -401,10 +401,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} else if (value is Comp) {
return false; // comp returns 0 or 1, which always fits
} else if (value is IfInstruction ifInst) {
return IsImplicitTruncation(ifInst.TrueInst, type, allowNullableValue)
|| IsImplicitTruncation(ifInst.FalseInst, type, allowNullableValue);
return IsImplicitTruncation(ifInst.TrueInst, type, compilation, allowNullableValue)
|| IsImplicitTruncation(ifInst.FalseInst, type, compilation, allowNullableValue);
} else {
IType inferredType = value.InferType();
IType inferredType = value.InferType(compilation);
if (allowNullableValue) {
inferredType = NullableType.GetUnderlyingType(inferredType);
}
@ -456,14 +456,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -456,14 +456,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// <summary>
/// Gets whether 'inst' is a possible store for use as a compound store.
/// </summary>
static bool IsCompoundStore(ILInstruction inst, out IType storeType, out ILInstruction value)
static bool IsCompoundStore(ILInstruction inst, out IType storeType, out ILInstruction value, ICompilation compilation)
{
value = null;
storeType = null;
if (inst is StObj stobj) {
// stobj.Type may just be 'int' (due to stind.i4) when we're actually operating on a 'ref MyEnum'.
// Try to determine the real type of the object we're modifying:
storeType = stobj.Target.InferType();
storeType = stobj.Target.InferType(compilation);
if (storeType is ByReferenceType refType) {
storeType = refType.ElementType;
} else if (storeType is PointerType pointerType) {
@ -530,7 +530,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -530,7 +530,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
bool TransformPostIncDecOperatorWithInlineStore(Block block, int pos)
{
var store = block.Instructions[pos];
if (!IsCompoundStore(store, out var targetType, out var value))
if (!IsCompoundStore(store, out var targetType, out var value, context.TypeSystem))
return false;
StLoc stloc;
var binary = UnwrapSmallIntegerConv(value, out var conv) as BinaryNumericInstruction;
@ -555,7 +555,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -555,7 +555,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!IsMatchingCompoundLoad(stloc.Value, store, stloc.Variable))
return false;
if (IsImplicitTruncation(stloc.Value, stloc.Variable.Type))
if (IsImplicitTruncation(stloc.Value, stloc.Variable.Type, context.TypeSystem))
return false;
context.Step("TransformPostIncDecOperatorWithInlineStore", store);
if (binary != null) {
@ -585,9 +585,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -585,9 +585,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var store = block.Instructions.ElementAtOrDefault(i + 1);
if (inst == null || store == null)
return false;
if (!IsCompoundStore(store, out var targetType, out var value))
if (!IsCompoundStore(store, out var targetType, out var value, context.TypeSystem))
return false;
if (IsImplicitTruncation(inst.Value, targetType)) {
if (IsImplicitTruncation(inst.Value, targetType, context.TypeSystem)) {
// 'stloc l' is implicitly truncating the value
return false;
}

2
ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

@ -1065,7 +1065,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1065,7 +1065,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
value = call.Arguments[0];
if (call.Arguments.Count == 2)
return MatchGetTypeFromHandle(call.Arguments[1], out type);
type = value.InferType();
type = value.InferType(context.TypeSystem);
return true;
}
return false;

Loading…
Cancel
Save