From 8de27deb9e1397114bbc343ddfe7dcfc4125ebfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 24 Feb 2011 00:56:40 +0000 Subject: [PATCH] Reduced the complexity of short-circuit detection to polynomial time. Closes #24 Closes #29 --- .../Ast/AstMethodBodyBuilder.cs | 60 ++-- .../ILAst/ILAstOptimizer.cs | 320 +++++++++--------- ICSharpCode.Decompiler/ILAst/ILCodes.cs | 4 +- ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs | 6 +- 4 files changed, 201 insertions(+), 189 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index eabbc2203..e36d251ff 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -181,13 +181,13 @@ namespace Decompiler switch(expr.Code) { case ILCode.LogicNot: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, MakeBranchCondition(expr.Arguments[0])); - case ILCode.LogicAnd: + case ILCode.BrLogicAnd: return new Ast.BinaryOperatorExpression( MakeBranchCondition(expr.Arguments[0]), BinaryOperatorType.ConditionalAnd, MakeBranchCondition(expr.Arguments[1]) ); - case ILCode.LogicOr: + case ILCode.BrLogicOr: return new Ast.BinaryOperatorExpression( MakeBranchCondition(expr.Arguments[0]), BinaryOperatorType.ConditionalOr, @@ -255,8 +255,7 @@ namespace Decompiler AstNode TransformExpression(ILExpression expr) { - List args = TransformExpressionArguments(expr); - AstNode node = TransformByteCode(expr, args); + AstNode node = TransformByteCode(expr); Expression astExpr = node as Expression; if (astExpr != null) return Convert(astExpr, expr.InferredType, expr.ExpectedType); @@ -264,22 +263,44 @@ namespace Decompiler return node; } - AstNode TransformByteCode(ILExpression byteCode, List args) + 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) + } + }; + } + + 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; - BlockStatement branchCommand = null; - if (byteCode.Operand is ILLabel) { - branchCommand = new BlockStatement(); - branchCommand.Add(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name)); - } - switch((Code)opCode) { #region Arithmetic case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); @@ -344,25 +365,10 @@ namespace Decompiler case Code.Stelem_Any: return InlineAssembly(byteCode, args); #endregion - #region Branching - case Code.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name); - case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1), branchCommand); - case Code.Brtrue: return new Ast.IfElseStatement(arg1, branchCommand); - case Code.Beq: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), branchCommand); - case Code.Bge: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand); - case Code.Bge_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand); - case Code.Bgt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand); - case Code.Bgt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand); - case Code.Ble: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand); - case Code.Ble_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand); - case Code.Blt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand); - case Code.Blt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand); - case Code.Bne_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), branchCommand); - #endregion #region Comparison case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); case Code.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); - case Code.Cgt_Un: + case Code.Cgt_Un: // can also mean Inequality, when used with object references { TypeReference arg1Type = byteCode.Arguments[0].InferredType; diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index 1d0e2785a..a218acf91 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; + using ICSharpCode.Decompiler.FlowAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; @@ -22,7 +24,6 @@ namespace Decompiler.ControlFlow public class ILAstOptimizer { Dictionary labelToCfNode = new Dictionary(); - Dictionary labelRefCount; public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None) { @@ -31,8 +32,9 @@ namespace Decompiler.ControlFlow SplitToBasicBlocks(block); } + OptimizeShortCircuits(method); + if (abortBeforeStep == ILAstOptimizationStep.FindLoops) return; - UpdateLabelRefCounts(method); foreach(ILBlock block in method.GetSelfAndChildrenRecursive().ToList()) { ControlFlowGraph graph; graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); @@ -42,7 +44,6 @@ namespace Decompiler.ControlFlow } if (abortBeforeStep == ILAstOptimizationStep.FindConditions) return; - UpdateLabelRefCounts(method); foreach(ILBlock block in method.GetSelfAndChildrenRecursive().ToList()) { ControlFlowGraph graph; graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); @@ -99,8 +100,8 @@ namespace Decompiler.ControlFlow // Insert split if (currNode is ILLabel || - lastNode is ILTryCatchBlock || - currNode is ILTryCatchBlock || + lastNode is ILTryCatchBlock || + currNode is ILTryCatchBlock || (lastNode is ILExpression) && ((ILExpression)lastNode).IsBranch() || (currNode is ILExpression) && (((ILExpression)currNode).IsBranch() && basicBlock.Body.Count > 0)) { @@ -131,6 +132,109 @@ namespace Decompiler.ControlFlow return; } + void OptimizeShortCircuits(ILBlock method) + { + AnalyseLabels(method); + + foreach(ILBlock block in method.GetSelfAndChildrenRecursive().ToList()) { + bool modified; + do { + modified = false; + for (int i = 0; i < block.Body.Count;) { + if (TrySimplifyShortCircuit(block.Body, (ILBasicBlock)block.Body[i])) { + modified = true; + } else { + i++; + } + } + } while(modified); + } + } + + Dictionary labelGlobalRefCount; + Dictionary labelToBasicBlock; + + void AnalyseLabels(ILBlock method) + { + labelGlobalRefCount = new Dictionary(); + foreach(ILLabel target in method.GetSelfAndChildrenRecursive().SelectMany(e => e.GetBranchTargets())) { + if (!labelGlobalRefCount.ContainsKey(target)) + labelGlobalRefCount[target] = 0; + labelGlobalRefCount[target]++; + } + + labelToBasicBlock = new Dictionary(); + foreach(ILBasicBlock bb in method.GetSelfAndChildrenRecursive()) { + foreach(ILLabel label in bb.GetChildren().OfType()) { + labelToBasicBlock[label] = bb; + } + } + } + + 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) { + trueLabel = (ILLabel)branchExpr.Operand; + falseLabel = (ILLabel)((ILExpression)bb.FallthoughGoto).Operand; + return true; + } + } + return false; + } + + // scope is modified if successful + bool TrySimplifyShortCircuit(List scope, ILBasicBlock head) + { + Debug.Assert(scope.Contains(head)); + + ILExpression branchExpr = null; + ILLabel trueLabel = null; + ILLabel falseLabel = null; + if(IsConditionalBranch(head, ref branchExpr, ref trueLabel, ref falseLabel)) { + for (int pass = 0; pass < 2; pass++) { + + // On the second pass, swap labels and negate expression of the first branch + // It is slightly ugly, but much better then copy-pasting this whole block + ILLabel nextLabel = (pass == 0) ? trueLabel : falseLabel; + ILLabel otherLablel = (pass == 0) ? falseLabel : trueLabel; + bool negate = (pass == 1); + + ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel]; + ILExpression nextBranchExpr = null; + ILLabel nextTrueLablel = null; + ILLabel nextFalseLabel = null; + if (scope.Contains(nextBasicBlock) && + nextBasicBlock != head && + labelGlobalRefCount[nextBasicBlock.EntryLabel] == 1 && + IsConditionalBranch(nextBasicBlock, ref nextBranchExpr, ref nextTrueLablel, ref 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); + } else { + head.Body[0] = new ILExpression(ILCode.BrLogicOr, nextTrueLablel, negate ? branchExpr : new ILExpression(ILCode.LogicNot, null, branchExpr), nextBranchExpr); + } + head.FallthoughGoto = new ILExpression(ILCode.Br, nextFalseLabel); + + // Remove the inlined branch from scope + labelGlobalRefCount[nextBasicBlock.EntryLabel] = 0; + if (!scope.Remove(nextBasicBlock)) + throw new Exception("Element not found"); + + return true; + } + } + } + return false; + } + ControlFlowGraph BuildGraph(List nodes, ILLabel entryLabel) { int index = 0; @@ -203,24 +307,27 @@ namespace Decompiler.ControlFlow ControlFlowNode node = agenda.Dequeue(); if (scope.Contains(node) - && node.DominanceFrontier.Contains(node) - && (node != entryPoint || !excludeEntryPoint)) + && node.DominanceFrontier.Contains(node) + && (node != entryPoint || !excludeEntryPoint)) { HashSet loopContents = FindDominatedNodes(scope, node); ILWhileLoop loop = new ILWhileLoop(); - ILCondition cond; - HashSet condNodes; - ILLabel condLabel; - if (TryMatchCondition(loopContents, new ControlFlowNode[]{}, node, out cond, out condNodes, out condLabel)) { - loopContents.ExceptWith(condNodes); - scope.ExceptWith(condNodes); + ILBasicBlock basicBlock = node.UserData as ILBasicBlock; + ILExpression branchExpr = null; + ILLabel trueLabel = null; + ILLabel falseLabel = null; + if(basicBlock != null && IsConditionalBranch(basicBlock, ref branchExpr, ref trueLabel, ref falseLabel)) { + loopContents.Remove(node); + scope.Remove(node); + branchExpr.Operand = null; // Do not keep label alive + // Use loop to implement condition - loop.Condition = cond.Condition; - loop.PreLoopLabel = condLabel; - loop.PostLoopGoto = cond.FalseBlock.EntryGoto; - loop.BodyBlock = new ILBlock() { EntryGoto = cond.TrueBlock.EntryGoto }; + loop.Condition = branchExpr; + loop.PreLoopLabel = basicBlock.EntryLabel; + loop.PostLoopGoto = new ILExpression(ILCode.Br, falseLabel); + loop.BodyBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) }; } else { // Give the block some explicit entry point ILLabel entryLabel = new ILLabel() { Name = "Loop_" + (nextBlockIndex++) }; @@ -249,16 +356,6 @@ namespace Decompiler.ControlFlow return result; } - void UpdateLabelRefCounts(ILBlock method) - { - labelRefCount = new Dictionary(); - foreach(ILLabel target in method.GetSelfAndChildrenRecursive().SelectMany(e => e.GetBranchTargets())) { - if (!labelRefCount.ContainsKey(target)) - labelRefCount[target] = 0; - labelRefCount[target]++; - } - } - List FindConditions(HashSet scope, ControlFlowNode entryNode) { List result = new List(); @@ -288,11 +385,25 @@ namespace Decompiler.ControlFlow // Switch if (condBranch != null && condBranch.Operand is ILLabel[] && condBranch.Arguments.Count > 0) { + ILLabel[] caseLabels = (ILLabel[])condBranch.Operand; + + // The labels will not be used - kill them + condBranch.Operand = null; + ILSwitch ilSwitch = new ILSwitch() { Condition = condBranch, DefaultGoto = block.FallthoughGoto }; + result.Add(new ILBasicBlock() { + EntryLabel = block.EntryLabel, // Keep the entry label + Body = { ilSwitch } + }); + + // Remove the item so that it is not picked up as content + if (!scope.Remove(node)) + throw new Exception("Item is not in set"); + // Pull in code of cases ControlFlowNode fallTarget = null; labelToCfNode.TryGetValue((ILLabel)block.FallthoughGoto.Operand, out fallTarget); @@ -300,14 +411,14 @@ namespace Decompiler.ControlFlow if (fallTarget != null) frontiers.UnionWith(fallTarget.DominanceFrontier); - foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) { + foreach(ILLabel condLabel in caseLabels) { ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null) frontiers.UnionWith(condTarget.DominanceFrontier); } - foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) { + foreach(ILLabel condLabel in caseLabels) { ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); @@ -321,34 +432,36 @@ namespace Decompiler.ControlFlow } ilSwitch.CaseBlocks.Add(caseBlock); } + } + + // Two-way branch + ILExpression branchExpr = null; + ILLabel trueLabel = null; + ILLabel falseLabel = null; + if(IsConditionalBranch(block, ref branchExpr, ref trueLabel, ref falseLabel)) { - // The labels will not be used - kill them - condBranch.Operand = null; + // The branch label will not be used - kill it + branchExpr.Operand = null; + // Convert the basic block to ILCondition + ILCondition ilCond = new ILCondition() { + Condition = branchExpr, + TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) }, + FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) } + }; result.Add(new ILBasicBlock() { - EntryLabel = block.EntryLabel, // Keep the entry label - Body = { ilSwitch } + EntryLabel = block.EntryLabel, // Keep the entry label + Body = { ilCond } }); - scope.Remove(node); - } - - // Two-way branch - ILCondition ilCond; - HashSet matchedNodes; - ILLabel condEntryLabel; - if (TryMatchCondition(scope, new ControlFlowNode[] {}, node, out ilCond, out matchedNodes, out condEntryLabel)) { - // The branch labels will not be used - kill them - foreach(ILExpression expr in ilCond.Condition.GetSelfAndChildrenRecursive()) { - if (expr.GetBranchTargets().Any()) { - expr.Operand = null; - } - } + // 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"); ControlFlowNode trueTarget = null; - labelToCfNode.TryGetValue((ILLabel)ilCond.TrueBlock.EntryGoto.Operand, out trueTarget); + labelToCfNode.TryGetValue(trueLabel, out trueTarget); ControlFlowNode falseTarget = null; - labelToCfNode.TryGetValue((ILLabel)ilCond.FalseBlock.EntryGoto.Operand, out falseTarget); + labelToCfNode.TryGetValue(falseLabel, out falseTarget); // Pull in the conditional code HashSet frontiers = new HashSet(); @@ -367,12 +480,6 @@ namespace Decompiler.ControlFlow scope.ExceptWith(content); ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget)); } - - result.Add(new ILBasicBlock() { - EntryLabel = condEntryLabel, // Keep the entry label - Body = { ilCond } - }); - scope.ExceptWith(matchedNodes); } } @@ -397,107 +504,6 @@ namespace Decompiler.ControlFlow return result; } - bool TryMatchCondition(HashSet scope, IEnumerable scopeExcept, ControlFlowNode head, out ILCondition condition, out HashSet matchedNodes, out ILLabel entryLabel) - { - condition = null; - matchedNodes = null; - entryLabel = null; - if (!scope.Contains(head) || scopeExcept.Contains(head)) - return false; - - ILBasicBlock basicBlock = head.UserData as ILBasicBlock; - - if (basicBlock == null || basicBlock.Body.Count != 1) - return false; - - ILExpression condBranch = basicBlock.Body[0] as ILExpression; - - if (condBranch != null && condBranch.Operand is ILLabel && condBranch.Arguments.Count > 0) { - - // We have found a two-way condition - condition = new ILCondition() { - Condition = condBranch, - TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, condBranch.Operand) }, - FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, basicBlock.FallthoughGoto.Operand) } - }; - // We are done with the node so "remove" it from scope - scopeExcept = scopeExcept.Union(new[] {head}); - matchedNodes = new HashSet() { head }; - entryLabel = basicBlock.EntryLabel; - - // Optimize short-circut expressions - while(true) { - - // Consider condition.TrueBlock - { - ILLabel nextLabel = (ILLabel)condition.TrueBlock.EntryGoto.Operand; - ControlFlowNode nextTarget; - labelToCfNode.TryGetValue(nextLabel, out nextTarget); - ILCondition nextCond; - HashSet nextMatchedNodes; - ILLabel nextEnteryLabel; - if (nextTarget != null && - TryMatchCondition(scope, scopeExcept, nextTarget, out nextCond, out nextMatchedNodes, out nextEnteryLabel) && - labelRefCount[nextEnteryLabel] == 1) - { - if (condition.FalseBlock.EntryGoto.Operand == nextCond.FalseBlock.EntryGoto.Operand) { - condition.Condition = new ILExpression(ILCode.LogicAnd, null, condition.Condition, nextCond.Condition); - condition.TrueBlock = nextCond.TrueBlock; - condition.FalseBlock = nextCond.FalseBlock; - scopeExcept = scopeExcept.Union(nextMatchedNodes); - matchedNodes.UnionWith(nextMatchedNodes); - continue; - } - - if (condition.FalseBlock.EntryGoto.Operand == nextCond.TrueBlock.EntryGoto.Operand) { - condition.Condition = new ILExpression(ILCode.LogicOr, null, new ILExpression(ILCode.LogicNot, null, condition.Condition), nextCond.Condition); - condition.TrueBlock = nextCond.TrueBlock; - condition.FalseBlock = nextCond.FalseBlock; - scopeExcept = scopeExcept.Union(nextMatchedNodes); - matchedNodes.UnionWith(nextMatchedNodes); - continue; - } - } - } - - // Consider condition.FalseBlock - { - ILLabel nextLabel = (ILLabel)condition.FalseBlock.EntryGoto.Operand; - ControlFlowNode nextTarget; - labelToCfNode.TryGetValue(nextLabel, out nextTarget); - ILCondition nextCond; - HashSet nextMatchedNodes; - ILLabel nextEnteryLabel; - if (nextTarget != null && - TryMatchCondition(scope, scopeExcept, nextTarget, out nextCond, out nextMatchedNodes, out nextEnteryLabel) && - labelRefCount[nextEnteryLabel] == 1) - { - if (condition.TrueBlock.EntryGoto.Operand == nextCond.FalseBlock.EntryGoto.Operand) { - condition.Condition = new ILExpression(ILCode.LogicAnd, null, new ILExpression(ILCode.LogicNot, null, condition.Condition), nextCond.Condition); - condition.TrueBlock = nextCond.TrueBlock; - condition.FalseBlock = nextCond.FalseBlock; - scopeExcept = scopeExcept.Union(nextMatchedNodes); - matchedNodes.UnionWith(nextMatchedNodes); - continue; - } - - if (condition.TrueBlock.EntryGoto.Operand == nextCond.TrueBlock.EntryGoto.Operand) { - condition.Condition = new ILExpression(ILCode.LogicOr, null, condition.Condition, nextCond.Condition); - condition.TrueBlock = nextCond.TrueBlock; - condition.FalseBlock = nextCond.FalseBlock; - scopeExcept = scopeExcept.Union(nextMatchedNodes); - matchedNodes.UnionWith(nextMatchedNodes); - continue; - } - } - } - break; - } - return true; - } - return false; - } - static HashSet FindDominatedNodes(HashSet scope, ControlFlowNode head) { var exitNodes = head.DominanceFrontier.SelectMany(n => n.Predecessors); @@ -507,7 +513,7 @@ namespace Decompiler.ControlFlow while(agenda.Count > 0) { ControlFlowNode addNode = agenda.First(); agenda.Remove(addNode); - + if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode)) { foreach (var predecessor in addNode.Predecessors) { agenda.Add(predecessor); diff --git a/ICSharpCode.Decompiler/ILAst/ILCodes.cs b/ICSharpCode.Decompiler/ILAst/ILCodes.cs index 2f4de5351..4e4160b56 100644 --- a/ICSharpCode.Decompiler/ILAst/ILCodes.cs +++ b/ICSharpCode.Decompiler/ILAst/ILCodes.cs @@ -256,8 +256,8 @@ namespace Decompiler // Virtual codes - defined for convenience Ldexception, // Operand holds the CatchType for catch handler, null for filter LogicNot, - LogicAnd, - LogicOr + BrLogicAnd, + BrLogicOr } public static class ILCodeUtil diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index e7ed4a7dd..9cfadabe2 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -112,13 +112,13 @@ namespace Decompiler InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); } return typeSystem.Boolean; - case ILCode.LogicAnd: - case ILCode.LogicOr: + case ILCode.BrLogicAnd: + case ILCode.BrLogicOr: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); } - return typeSystem.Boolean; + return null; #endregion #region Variable load/store case ILCode.Stloc: