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
/// ///
/// Returns SpecialType.UnknownType for unsupported instructions. /// Returns SpecialType.UnknownType for unsupported instructions.
/// </summary> /// </summary>
public static IType InferType(this ILInstruction inst) public static IType InferType(this ILInstruction inst, ICompilation compilation)
{ {
switch (inst) { switch (inst) {
case NewObj newObj: case NewObj newObj:
@ -159,12 +159,24 @@ namespace ICSharpCode.Decompiler.IL
case LdsFlda ldsflda: case LdsFlda ldsflda:
return new ByReferenceType(ldsflda.Field.Type); return new ByReferenceType(ldsflda.Field.Type);
case LdElema ldelema: 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)) { if (TypeUtils.IsCompatibleTypeForMemoryAccess(arrayType.ElementType, ldelema.Type)) {
return new ByReferenceType(arrayType.ElementType); return new ByReferenceType(arrayType.ElementType);
} }
} }
return new ByReferenceType(ldelema.Type); 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: default:
return SpecialType.UnknownType; return SpecialType.UnknownType;
} }

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

@ -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. // 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 false;
return true; return true;
} }

21
ICSharpCode.Decompiler/IL/SemanticHelper.cs

@ -44,27 +44,6 @@ namespace ICSharpCode.Decompiler.IL
return (inst & ~pureFlags) == 0; 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> /// <summary>
/// Gets whether the instruction sequence 'inst1; inst2;' may be ordered to 'inst2; inst1;' /// Gets whether the instruction sequence 'inst1; inst2;' may be ordered to 'inst2; inst1;'
/// </summary> /// </summary>

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

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

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

@ -498,7 +498,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
break; break;
case BinaryNumericOperator.BitAnd: 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); context.Step("Replace bit.and with logic.and", inst);
var expr = IfInstruction.LogicAnd(inst.Left, inst.Right); var expr = IfInstruction.LogicAnd(inst.Left, inst.Right);
@ -508,11 +510,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
break; 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) protected internal override void VisitTryCatchHandler(TryCatchHandler inst)
{ {
base.VisitTryCatchHandler(inst); base.VisitTryCatchHandler(inst);

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

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

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

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

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

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

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

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

Loading…
Cancel
Save