diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 65b2b9d27..b25fe1cb5 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -108,7 +108,7 @@ namespace ICSharpCode.Decompiler.Ast } else if (node is ILWhileLoop) { ILWhileLoop ilLoop = (ILWhileLoop)node; WhileStatement whileStmt = new WhileStatement() { - Condition = ilLoop.Condition != null ? MakeBranchCondition(ilLoop.Condition) : new PrimitiveExpression(true), + Condition = ilLoop.Condition != null ? (Expression)TransformExpression(ilLoop.Condition) : new PrimitiveExpression(true), EmbeddedStatement = TransformBlock(ilLoop.BodyBlock) }; yield return whileStmt; @@ -116,7 +116,7 @@ namespace ICSharpCode.Decompiler.Ast ILCondition conditionalNode = (ILCondition)node; bool hasFalseBlock = conditionalNode.FalseBlock.EntryGoto != null || conditionalNode.FalseBlock.Body.Count > 0; yield return new Ast.IfElseStatement { - Condition = MakeBranchCondition(conditionalNode.Condition), + Condition = (Expression)TransformExpression(conditionalNode.Condition), TrueStatement = TransformBlock(conditionalNode.TrueBlock), FalseStatement = hasFalseBlock ? TransformBlock(conditionalNode.FalseBlock) : null }; @@ -166,58 +166,6 @@ namespace ICSharpCode.Decompiler.Ast return args; } - Ast.Expression MakeBranchCondition(ILExpression expr) - { - switch(expr.Code) { - case ILCode.LogicNot: - return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, MakeBranchCondition(expr.Arguments[0])); - case ILCode.BrLogicAnd: - return new Ast.BinaryOperatorExpression( - MakeBranchCondition(expr.Arguments[0]), - BinaryOperatorType.ConditionalAnd, - MakeBranchCondition(expr.Arguments[1]) - ); - case ILCode.BrLogicOr: - return new Ast.BinaryOperatorExpression( - MakeBranchCondition(expr.Arguments[0]), - BinaryOperatorType.ConditionalOr, - MakeBranchCondition(expr.Arguments[1]) - ); - } - - List args = TransformExpressionArguments(expr); - Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; - Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; - switch((Code)expr.Code) { - case Code.Brfalse: - return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1); - case Code.Brtrue: - return arg1; - case Code.Beq: - return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); - case Code.Bge: - return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); - case Code.Bge_Un: - return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); - case Code.Bgt: - return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); - case Code.Bgt_Un: - return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); - case Code.Ble: - return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); - case Code.Ble_Un: - return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); - case Code.Blt: - return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); - case Code.Blt_Un: - return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); - case Code.Bne_Un: - return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); - default: - throw new Exception("Bad opcode"); - } - } - static string FormatByteCodeOperand(object operand) { if (operand == null) { @@ -255,53 +203,15 @@ namespace ICSharpCode.Decompiler.Ast AstNode TransformByteCode(ILExpression byteCode) { - ILCode opCode = byteCode.Code; object operand = byteCode.Operand; AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference); - ILExpression operandAsByteCode = operand as ILExpression; - // Do branches first because TransformExpressionArguments does not work on arguments that are branches themselfs - // TODO: We should probably have virtual instructions for these and not abuse branch codes as expressions - switch(opCode) { - case ILCode.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name); - case ILCode.Brfalse: - case ILCode.Brtrue: - case ILCode.Beq: - case ILCode.Bge: - case ILCode.Bge_Un: - case ILCode.Bgt: - case ILCode.Bgt_Un: - case ILCode.Ble: - case ILCode.Ble_Un: - case ILCode.Blt: - case ILCode.Blt_Un: - case ILCode.Bne_Un: - case ILCode.BrLogicAnd: - case ILCode.BrLogicOr: - return new Ast.IfElseStatement() { - Condition = MakeBranchCondition(byteCode), - TrueStatement = new BlockStatement() { - new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name) - } - }; - case ILCode.TernaryOp: - return new Ast.ConditionalExpression() { - Condition = MakeBranchCondition(byteCode.Arguments[0]), - TrueExpression = (Expression)TransformExpression(byteCode.Arguments[1]), - FalseExpression = (Expression)TransformExpression(byteCode.Arguments[2]), - }; - case ILCode.LoopBreak: - return new Ast.BreakStatement(); - case ILCode.LoopContinue: - return new Ast.ContinueStatement(); - } - List args = TransformExpressionArguments(byteCode); Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; Ast.Expression arg3 = args.Count >= 3 ? args[2] : null; - switch(opCode) { + switch(byteCode.Code) { #region Arithmetic case ILCode.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case ILCode.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); @@ -337,7 +247,7 @@ namespace ICSharpCode.Decompiler.Ast // change "new (int[,])[10] to new int[10][,]" ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); } - if (opCode == ILCode.InitArray) { + if (byteCode.Code == ILCode.InitArray) { ace.Initializer = new ArrayInitializerExpression(); ace.Initializer.Elements.AddRange(args); } else { @@ -392,6 +302,24 @@ namespace ICSharpCode.Decompiler.Ast return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); case ILCode.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); + #endregion + #region Logical + case ILCode.LogicNot: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1); + case ILCode.LogicAnd: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalAnd, arg2); + case ILCode.LogicOr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalOr, arg2); + case ILCode.TernaryOp: return new Ast.ConditionalExpression() { Condition = arg1, TrueExpression = arg2, FalseExpression = arg3 }; + #endregion + #region Branch + case ILCode.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name); + case ILCode.Brtrue: + return new Ast.IfElseStatement() { + Condition = arg1, + TrueStatement = new BlockStatement() { + new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name) + } + }; + case ILCode.LoopBreak: return new Ast.BreakStatement(); + case ILCode.LoopContinue: return new Ast.ContinueStatement(); #endregion #region Conversions case ILCode.Conv_I1: @@ -629,7 +557,7 @@ namespace ICSharpCode.Decompiler.Ast case ILCode.Throw: return new Ast.ThrowStatement { Expression = arg1 }; case ILCode.Unaligned: return InlineAssembly(byteCode, args); case ILCode.Volatile: return InlineAssembly(byteCode, args); - default: throw new Exception("Unknown OpCode: " + opCode); + default: throw new Exception("Unknown OpCode: " + byteCode.Code); } } diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index ef2c1a4b9..716aae0fb 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -11,6 +11,7 @@ namespace ICSharpCode.Decompiler.ILAst { public enum ILAstOptimizationStep { + ReduceBranchInstructionSet, SplitToMovableBlocks, PeepholeOptimizations, FindLoops, @@ -32,6 +33,11 @@ namespace ICSharpCode.Decompiler.ILAst public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None) { + if (abortBeforeStep == ILAstOptimizationStep.ReduceBranchInstructionSet) return; + foreach(ILBlock block in method.GetSelfAndChildrenRecursive().ToList()) { + ReduceBranchInstructionSet(block); + } + if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) return; foreach(ILBlock block in method.GetSelfAndChildrenRecursive().ToList()) { SplitToBasicBlocks(block); @@ -85,6 +91,39 @@ namespace ICSharpCode.Decompiler.ILAst GotoRemoval.RemoveRedundantCode(method); } + /// + /// Reduces the branch codes to just br and brtrue. + /// Moves ILRanges to the branch argument + /// + void ReduceBranchInstructionSet(ILBlock block) + { + for (int i = 0; i < block.Body.Count; i++) { + ILExpression expr = block.Body[i] as ILExpression; + if (expr != null && expr.Prefixes == null) { + switch(expr.Code) { + case ILCode.Brtrue: + expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges); + expr.ILRanges.Clear(); + continue; + case ILCode.__Brfalse: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, expr.Arguments.Single())); break; + case ILCode.__Beq: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Ceq, null, expr.Arguments)); break; + case ILCode.__Bne_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Ceq, null, expr.Arguments))); break; + case ILCode.__Bgt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt, null, expr.Arguments)); break; + case ILCode.__Bgt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments)); break; + case ILCode.__Ble: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt, null, expr.Arguments))); break; + case ILCode.__Ble_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments))); break; + case ILCode.__Blt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt, null, expr.Arguments)); break; + case ILCode.__Blt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt_Un, null, expr.Arguments)); break; + case ILCode.__Bge: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt, null, expr.Arguments))); break; + case ILCode.__Bge_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt_Un, null, expr.Arguments))); break; + default: + continue; + } + ((ILExpression)block.Body[i]).Arguments.Single().ILRanges.AddRange(expr.ILRanges); + } + } + } + /// /// Group input into a set of blocks that can be later arbitraliby schufled. /// The method adds necessary branches to make control flow between blocks @@ -196,31 +235,11 @@ namespace ICSharpCode.Decompiler.ILAst } while(modified); } - bool IsConditionalBranch(ILBasicBlock bb, ref ILExpression branchExpr, ref ILLabel trueLabel, ref ILLabel falseLabel) - { - if (bb.Body.Count == 1) { - branchExpr = bb.Body[0] as ILExpression; - if (branchExpr != null && - branchExpr.Operand is ILLabel && - branchExpr.Arguments.Count > 0 && - branchExpr.Prefixes == null) - { - trueLabel = (ILLabel)branchExpr.Operand; - falseLabel = (ILLabel)((ILExpression)bb.FallthoughGoto).Operand; - return true; - } - } - return false; - } - bool IsStloc(ILBasicBlock bb, ref ILVariable locVar, ref ILExpression val, ref ILLabel fallLabel) { if (bb.Body.Count == 1) { - ILExpression expr = bb.Body[0] as ILExpression; - if (expr != null && - expr.Code == ILCode.Stloc && - expr.Prefixes == null) - { + ILExpression expr; + if (bb.Body[0].Match(ILCode.Stloc, out expr)) { locVar = (ILVariable)expr.Operand; val = expr.Arguments[0]; fallLabel = (ILLabel)bb.FallthoughGoto.Operand; @@ -235,7 +254,7 @@ namespace ICSharpCode.Decompiler.ILAst { Debug.Assert(scope.Contains(head)); - ILExpression branchExpr = null; + ILExpression condExpr = null; ILLabel trueLabel = null; ILLabel falseLabel = null; ILVariable trueLocVar = null; @@ -245,7 +264,7 @@ namespace ICSharpCode.Decompiler.ILAst ILExpression falseExpr = null; ILLabel falseFall = null; - if(IsConditionalBranch(head, ref branchExpr, ref trueLabel, ref falseLabel) && + if(head.MatchBrTure(out condExpr, out trueLabel, out falseLabel) && labelGlobalRefCount[trueLabel] == 1 && labelGlobalRefCount[falseLabel] == 1 && IsStloc(labelToBasicBlock[trueLabel], ref trueLocVar, ref trueExpr, ref trueFall) && @@ -254,24 +273,16 @@ namespace ICSharpCode.Decompiler.ILAst trueFall == falseFall) { // Create the ternary expression - head.Body = new List() { - new ILExpression(ILCode.Stloc, trueLocVar, - new ILExpression(ILCode.TernaryOp, null, - new ILExpression(branchExpr.Code, null, branchExpr.Arguments.ToArray()), - trueExpr, - falseExpr - ) - ) - }; + head.Body = new List() { new ILExpression(ILCode.Stloc, trueLocVar, new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr)) }; head.FallthoughGoto = new ILExpression(ILCode.Br, trueFall); // Remove the old basic blocks - scope.Remove(labelToBasicBlock[trueLabel]); - scope.Remove(labelToBasicBlock[falseLabel]); - labelToBasicBlock.Remove(trueLabel); - labelToBasicBlock.Remove(falseLabel); - labelGlobalRefCount.Remove(trueLabel); - labelGlobalRefCount.Remove(falseLabel); + scope.RemoveOrThrow(labelToBasicBlock[trueLabel]); + scope.RemoveOrThrow(labelToBasicBlock[falseLabel]); + labelToBasicBlock.RemoveOrThrow(trueLabel); + labelToBasicBlock.RemoveOrThrow(falseLabel); + labelGlobalRefCount.RemoveOrThrow(trueLabel); + labelGlobalRefCount.RemoveOrThrow(falseLabel); return true; } @@ -283,10 +294,10 @@ namespace ICSharpCode.Decompiler.ILAst { Debug.Assert(scope.Contains(head)); - ILExpression branchExpr = null; - ILLabel trueLabel = null; - ILLabel falseLabel = null; - if(IsConditionalBranch(head, ref branchExpr, ref trueLabel, ref falseLabel)) { + ILExpression condExpr; + ILLabel trueLabel; + ILLabel falseLabel; + if(head.MatchBrTure(out condExpr, out trueLabel, out falseLabel)) { for (int pass = 0; pass < 2; pass++) { // On the second pass, swap labels and negate expression of the first branch @@ -296,32 +307,27 @@ namespace ICSharpCode.Decompiler.ILAst bool negate = (pass == 1); ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel]; - ILExpression nextBranchExpr = null; - ILLabel nextTrueLablel = null; - ILLabel nextFalseLabel = null; + ILExpression nextCondExpr; + ILLabel nextTrueLablel; + ILLabel nextFalseLabel; if (scope.Contains(nextBasicBlock) && nextBasicBlock != head && labelGlobalRefCount[nextBasicBlock.EntryLabel] == 1 && - IsConditionalBranch(nextBasicBlock, ref nextBranchExpr, ref nextTrueLablel, ref nextFalseLabel) && + nextBasicBlock.MatchBrTure(out nextCondExpr, out nextTrueLablel, out nextFalseLabel) && (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel)) { - // We are using the branches as expressions now, so do not keep their labels alive - branchExpr.Operand = null; - nextBranchExpr.Operand = null; - // Create short cicuit branch if (otherLablel == nextFalseLabel) { - head.Body[0] = new ILExpression(ILCode.BrLogicAnd, nextTrueLablel, negate ? new ILExpression(ILCode.LogicNot, null, branchExpr) : branchExpr, nextBranchExpr); + head.Body[0] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicAnd, null, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr)); } else { - head.Body[0] = new ILExpression(ILCode.BrLogicOr, nextTrueLablel, negate ? branchExpr : new ILExpression(ILCode.LogicNot, null, branchExpr), nextBranchExpr); + head.Body[0] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicOr, null, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr)); } head.FallthoughGoto = new ILExpression(ILCode.Br, nextFalseLabel); // Remove the inlined branch from scope - labelGlobalRefCount.Remove(nextBasicBlock.EntryLabel); - labelToBasicBlock.Remove(nextBasicBlock.EntryLabel); - if (!scope.Remove(nextBasicBlock)) - throw new Exception("Element not found"); + labelGlobalRefCount.RemoveOrThrow(nextBasicBlock.EntryLabel); + labelToBasicBlock.RemoveOrThrow(nextBasicBlock.EntryLabel); + scope.RemoveOrThrow(nextBasicBlock); return true; } @@ -455,13 +461,12 @@ namespace ICSharpCode.Decompiler.ILAst HashSet loopContents = FindLoopContent(scope, node); ILBasicBlock basicBlock = (ILBasicBlock)node.UserData; - ILExpression branchExpr = null; - ILLabel trueLabel = null; - ILLabel falseLabel = null; - if(IsConditionalBranch(basicBlock, ref branchExpr, ref trueLabel, ref falseLabel)) { - loopContents.Remove(node); - scope.Remove(node); - branchExpr.Operand = null; // Do not keep label alive + ILExpression condExpr; + ILLabel trueLabel; + ILLabel falseLabel; + if(basicBlock.MatchBrTure(out condExpr, out trueLabel, out falseLabel)) { + loopContents.RemoveOrThrow(node); + scope.RemoveOrThrow(node); // TODO: Does 'true' really point into the loop body? Swap if necessary @@ -479,7 +484,7 @@ namespace ICSharpCode.Decompiler.ILAst EntryLabel = basicBlock.EntryLabel, Body = new List() { new ILWhileLoop() { - Condition = branchExpr, + Condition = condExpr, BodyBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel), Body = FindLoops(loopContents, node, true) @@ -567,8 +572,7 @@ namespace ICSharpCode.Decompiler.ILAst }); // Remove the item so that it is not picked up as content - if (!scope.Remove(node)) - throw new Exception("Item is not in set"); + scope.RemoveOrThrow(node); // Pull in code of cases ControlFlowNode fallTarget = null; @@ -602,23 +606,20 @@ namespace ICSharpCode.Decompiler.ILAst } // Two-way branch - ILExpression branchExpr = null; - ILLabel trueLabel = null; - ILLabel falseLabel = null; - if(IsConditionalBranch(block, ref branchExpr, ref trueLabel, ref falseLabel)) { - - // The branch label will not be used - kill it - branchExpr.Operand = null; + ILExpression condExpr; + ILLabel trueLabel; + ILLabel falseLabel; + if(block.MatchBrTure(out condExpr, out trueLabel, out falseLabel)) { // Swap bodies since that seems to be the usual C# order ILLabel temp = trueLabel; trueLabel = falseLabel; falseLabel = temp; - branchExpr = new ILExpression(ILCode.LogicNot, null, branchExpr); + condExpr = new ILExpression(ILCode.LogicNot, null, condExpr); // Convert the basic block to ILCondition ILCondition ilCond = new ILCondition() { - Condition = branchExpr, + Condition = condExpr, TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) }, FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) } }; @@ -628,8 +629,7 @@ namespace ICSharpCode.Decompiler.ILAst }); // Remove the item immediately so that it is not picked up as content - if (!scope.Remove(node)) - throw new Exception("Item is not in set"); + scope.RemoveOrThrow(node); ControlFlowNode trueTarget = null; labelToCfNode.TryGetValue(trueLabel, out trueTarget); @@ -811,10 +811,24 @@ namespace ICSharpCode.Decompiler.ILAst if (expr != null && expr.Prefixes == null && expr.Code == code) { operand = (T)expr.Operand; return true; - } else { - operand = default(T); - return false; } + operand = default(T); + return false; + } + + public static bool MatchBrTure(this ILBasicBlock bb, out ILExpression condition, out ILLabel trueLabel, out ILLabel falseLabel) + { + if (bb.Body.Count == 1) { + if (bb.Body[0].Match(ILCode.Brtrue, out trueLabel)) { + condition = ((ILExpression)bb.Body[0]).Arguments.Single(); + falseLabel = (ILLabel)((ILExpression)bb.FallthoughGoto).Operand; + return true; + } + } + condition = null; + trueLabel = null; + falseLabel = null; + return false; } public static bool CanFallthough(this ILNode node) @@ -833,5 +847,17 @@ namespace ICSharpCode.Decompiler.ILAst } return true; } + + public static void RemoveOrThrow(this ICollection collection, T item) + { + if (!collection.Remove(item)) + throw new Exception("The item was not found in the collection"); + } + + public static void RemoveOrThrow(this Dictionary collection, K key) + { + if (!collection.Remove(key)) + throw new Exception("The key was not found in the dictionary"); + } } } diff --git a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs index be7b7b763..6227fb92e 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs @@ -220,6 +220,14 @@ namespace ICSharpCode.Decompiler.ILAst public static readonly object AnyOperand = new object(); + public ILExpression(ILCode code, object operand, List args) + { + this.Code = code; + this.Operand = operand; + this.Arguments = new List(args); + this.ILRanges = new List(1); + } + public ILExpression(ILCode code, object operand, params ILExpression[] args) { this.Code = code; diff --git a/ICSharpCode.Decompiler/ILAst/ILCodes.cs b/ICSharpCode.Decompiler/ILAst/ILCodes.cs index 0304c3555..1d3201d3b 100644 --- a/ICSharpCode.Decompiler/ILAst/ILCodes.cs +++ b/ICSharpCode.Decompiler/ILAst/ILCodes.cs @@ -32,7 +32,7 @@ namespace ICSharpCode.Decompiler.ILAst public enum ILCode { // For convenience, the start is exactly identical to Mono.Cecil.Cil.Code - // The macro instructions should never be used and are therefore prepended by __ + // Instructions that should not be used are prepended by __ Nop, Break, __Ldarg_0, @@ -89,18 +89,18 @@ namespace ICSharpCode.Decompiler.ILAst __Ble_Un_S, __Blt_Un_S, Br, - Brfalse, + __Brfalse, Brtrue, - Beq, - Bge, - Bgt, - Ble, - Blt, - Bne_Un, - Bge_Un, - Bgt_Un, - Ble_Un, - Blt_Un, + __Beq, + __Bge, + __Bgt, + __Ble, + __Blt, + __Bne_Un, + __Bge_Un, + __Bgt_Un, + __Ble_Un, + __Blt_Un, Switch, Ldind_I1, Ldind_U1, @@ -256,8 +256,8 @@ namespace ICSharpCode.Decompiler.ILAst // Virtual codes - defined for convenience Ldexception, // Operand holds the CatchType for catch handler, null for filter LogicNot, - BrLogicAnd, - BrLogicOr, + LogicAnd, + LogicOr, InitArray, // Array Initializer TernaryOp, // ?: LoopBreak, @@ -271,7 +271,7 @@ namespace ICSharpCode.Decompiler.ILAst { public static string GetName(this ILCode code) { - return code.ToString().ToLowerInvariant().Replace('_','.'); + return code.ToString().ToLowerInvariant().TrimStart('_').Replace('_','.'); } public static bool CanFallThough(this ILCode code) @@ -396,18 +396,18 @@ namespace ICSharpCode.Decompiler.ILAst case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break; case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break; case ILCode.__Br_S: code = ILCode.Br; break; - case ILCode.__Brfalse_S: code = ILCode.Brfalse; break; + case ILCode.__Brfalse_S: code = ILCode.__Brfalse; break; case ILCode.__Brtrue_S: code = ILCode.Brtrue; break; - case ILCode.__Beq_S: code = ILCode.Beq; break; - case ILCode.__Bge_S: code = ILCode.Bge; break; - case ILCode.__Bgt_S: code = ILCode.Bgt; break; - case ILCode.__Ble_S: code = ILCode.Ble; break; - case ILCode.__Blt_S: code = ILCode.Blt; break; - case ILCode.__Bne_Un_S: code = ILCode.Bne_Un; break; - case ILCode.__Bge_Un_S: code = ILCode.Bge_Un; break; - case ILCode.__Bgt_Un_S: code = ILCode.Bgt_Un; break; - case ILCode.__Ble_Un_S: code = ILCode.Ble_Un; break; - case ILCode.__Blt_Un_S: code = ILCode.Blt_Un; break; + case ILCode.__Beq_S: code = ILCode.__Beq; break; + case ILCode.__Bge_S: code = ILCode.__Bge; break; + case ILCode.__Bgt_S: code = ILCode.__Bgt; break; + case ILCode.__Ble_S: code = ILCode.__Ble; break; + case ILCode.__Blt_S: code = ILCode.__Blt; break; + case ILCode.__Bne_Un_S: code = ILCode.__Bne_Un; break; + case ILCode.__Bge_Un_S: code = ILCode.__Bge_Un; break; + case ILCode.__Bgt_Un_S: code = ILCode.__Bgt_Un; break; + case ILCode.__Ble_Un_S: code = ILCode.__Ble_Un; break; + case ILCode.__Blt_Un_S: code = ILCode.__Blt_Un; break; case ILCode.__Leave_S: code = ILCode.Leave; break; } } diff --git a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs index 5dd6f98d4..31e1f1afb 100644 --- a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs +++ b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs @@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.ILAst #region CachedDelegateInitialization void CachedDelegateInitialization(ILBlock block, ref int i) { - // if (logicnot(brtrue(ldsfld(field)))) { + // if (logicnot(ldsfld(field))) { // stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method))) // } else { // } @@ -134,7 +134,9 @@ namespace ICSharpCode.Decompiler.ILAst return; if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0)) return; - ILExpression condition = UnpackBrFalse(c.Condition); + if (!c.Condition.Match(ILCode.LogicNot)) + return; + ILExpression condition = c.Condition.Arguments.Single() as ILExpression; if (condition == null || condition.Code != ILCode.Ldsfld) return; FieldDefinition field = condition.Operand as FieldDefinition; // field is defined in current assembly @@ -168,19 +170,6 @@ namespace ICSharpCode.Decompiler.ILAst } } } - - /// - /// Returns 'result' in brfalse(result) or logicnot(brtrue(result)). - /// - static ILExpression UnpackBrFalse(ILExpression condition) - { - if (condition.Code == ILCode.Brfalse) { - return condition.Arguments.Single(); - } else if (condition.Code == ILCode.LogicNot && condition.Arguments.Single().Code == ILCode.Brtrue) { - return condition.Arguments.Single().Arguments.Single(); - } - return null; - } #endregion } } diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index 2a1adf314..bed175b19 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -39,6 +39,14 @@ namespace ICSharpCode.Decompiler.ILAst void InferTypes(ILNode node) { + ILCondition cond = node as ILCondition; + if (cond != null) { + InferTypeForExpression(cond.Condition, typeSystem.Boolean, false); + } + ILWhileLoop loop = node as ILWhileLoop; + if (loop != null && loop.Condition != null) { + InferTypeForExpression(loop.Condition, typeSystem.Boolean, false); + } ILExpression expr = node as ILExpression; if (expr != null) { ILVariable v = expr.Operand as ILVariable; @@ -111,13 +119,13 @@ namespace ICSharpCode.Decompiler.ILAst InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); } return typeSystem.Boolean; - case ILCode.BrLogicAnd: - case ILCode.BrLogicOr: + case ILCode.LogicAnd: + case ILCode.LogicOr: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean); } - return null; + return typeSystem.Boolean; case ILCode.TernaryOp: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); @@ -438,30 +446,10 @@ namespace ICSharpCode.Decompiler.ILAst return typeSystem.Boolean; #endregion #region Branch instructions - case ILCode.Beq: - case ILCode.Bne_Un: - if (forceInferChildren) - InferArgumentsInBinaryOperator(expr, null); - return null; case ILCode.Brtrue: - case ILCode.Brfalse: if (forceInferChildren) InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); return null; - case ILCode.Blt: - case ILCode.Ble: - case ILCode.Bgt: - case ILCode.Bge: - if (forceInferChildren) - InferArgumentsInBinaryOperator(expr, true); - return null; - case ILCode.Blt_Un: - case ILCode.Ble_Un: - case ILCode.Bgt_Un: - case ILCode.Bge_Un: - if (forceInferChildren) - InferArgumentsInBinaryOperator(expr, false); - return null; case ILCode.Br: case ILCode.Leave: case ILCode.Endfinally: