List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entryNode)
		{
			List<ILNode> result = new List<ILNode>();
			
			// Do not modify entry data
			scope = new HashSet<ControlFlowNode>(scope);
			
			Stack<ControlFlowNode> agenda  = new Stack<ControlFlowNode>();
			agenda.Push(entryNode);
			while(agenda.Count > 0) {
				ControlFlowNode node = agenda.Pop();
				
				// Find a block that represents a simple condition
				if (scope.Contains(node)) {
					
					ILBasicBlock block = (ILBasicBlock)node.UserData;
					
					{
						// Switch
						ILLabel[] caseLabels;
						ILExpression switchArg;
						ILLabel fallLabel;
						if (block.MatchLastAndBr(ILCode.Switch, out caseLabels, out switchArg, out fallLabel)) {
							
							// Replace the switch code with ILSwitch
							ILSwitch ilSwitch = new ILSwitch() { Condition = switchArg };
							block.Body.RemoveTail(ILCode.Switch, ILCode.Br);
							block.Body.Add(ilSwitch);
							block.Body.Add(new ILExpression(ILCode.Br, fallLabel));
							result.Add(block);

							// Remove the item so that it is not picked up as content
							scope.RemoveOrThrow(node);
							
							// Find the switch offset
							int addValue = 0;
							List<ILExpression> subArgs;
							if (ilSwitch.Condition.Match(ILCode.Sub, out subArgs) && subArgs[1].Match(ILCode.Ldc_I4, out addValue)) {
								ilSwitch.Condition = subArgs[0];
							}
							
							// Pull in code of cases
							ControlFlowNode fallTarget = null;
							labelToCfNode.TryGetValue(fallLabel, out fallTarget);
							
							HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
							if (fallTarget != null)
								frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new [] { fallTarget }));
							
							foreach(ILLabel condLabel in caseLabels) {
								ControlFlowNode condTarget = null;
								labelToCfNode.TryGetValue(condLabel, out condTarget);
								if (condTarget != null)
									frontiers.UnionWith(condTarget.DominanceFrontier.Except(new [] { condTarget }));
							}
							
							for (int i = 0; i < caseLabels.Length; i++) {
								ILLabel condLabel = caseLabels[i];
								
								// Find or create new case block
								ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel);
								if (caseBlock == null) {
									caseBlock = new ILSwitch.CaseBlock() {
										Values = new List<int>(),
										EntryGoto = new ILExpression(ILCode.Br, condLabel)
									};
									ilSwitch.CaseBlocks.Add(caseBlock);
									
									ControlFlowNode condTarget = null;
									labelToCfNode.TryGetValue(condLabel, out condTarget);
									if (condTarget != null && !frontiers.Contains(condTarget)) {
										HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
										scope.ExceptWith(content);
										caseBlock.Body.AddRange(FindConditions(content, condTarget));
										// Add explicit break which should not be used by default, but the goto removal might decide to use it
										caseBlock.Body.Add(new ILBasicBlock() {
											Body = {
												new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) },
												new ILExpression(ILCode.LoopOrSwitchBreak, null)
											}
										});
									}
								}
								caseBlock.Values.Add(i + addValue);
							}
							
							// Heuristis to determine if we want to use fallthough as default case
							if (fallTarget != null && !frontiers.Contains(fallTarget)) {
								HashSet<ControlFlowNode> content = FindDominatedNodes(scope, fallTarget);
								if (content.Any()) {
									var caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, fallLabel) };
									ilSwitch.CaseBlocks.Add(caseBlock);
									block.Body.RemoveTail(ILCode.Br);
									
									scope.ExceptWith(content);
									caseBlock.Body.AddRange(FindConditions(content, fallTarget));
									// Add explicit break which should not be used by default, but the goto removal might decide to use it
									caseBlock.Body.Add(new ILBasicBlock() {
										Body = {
											new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) },
											new ILExpression(ILCode.LoopOrSwitchBreak, null)
										}
									});
								}
							}
						}
						
						// Two-way branch
						ILExpression condExpr;
						ILLabel trueLabel;
						ILLabel falseLabel;
						if(block.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
							
							// Swap bodies since that seems to be the usual C# order
							ILLabel temp = trueLabel;
							trueLabel = falseLabel;
							falseLabel = temp;
							condExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
							
							// Convert the brtrue to ILCondition
							ILCondition ilCond = new ILCondition() {
								Condition  = condExpr,
								TrueBlock  = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) },
								FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) }
							};
							block.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
							block.Body.Add(ilCond);
							result.Add(block);
							
							// Remove the item immediately so that it is not picked up as content
							scope.RemoveOrThrow(node);
							
							ControlFlowNode trueTarget = null;
							labelToCfNode.TryGetValue(trueLabel, out trueTarget);
							ControlFlowNode falseTarget = null;
							labelToCfNode.TryGetValue(falseLabel, out falseTarget);
							
							// Pull in the conditional code
							if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget)) {
								HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);
								scope.ExceptWith(content);
								ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget));
							}
							if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget)) {
								HashSet<ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
								scope.ExceptWith(content);
								ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget));
							}
						}
					}
					
					// Add the node now so that we have good ordering
					if (scope.Contains(node)) {
						result.Add((ILNode)node.UserData);
						scope.Remove(node);
					}
				}

				// depth-first traversal of dominator tree
				for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--) {
					agenda.Push(node.DominatorTreeChildren[i]);
				}
			}
			
			// Add whatever is left
			foreach(var node in scope) {
				result.Add((ILNode)node.UserData);
			}
			
			return result;
		}
Example #2
0
        List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entryNode)
        {
            List<ILNode> result = new List<ILNode>();

            // Do not modify entry data
            scope = new HashSet<ControlFlowNode>(scope);

            Stack<ControlFlowNode> agenda = new Stack<ControlFlowNode>();
            agenda.Push(entryNode);
            while (agenda.Count > 0)
            {
                ControlFlowNode node = agenda.Pop();

                // Find a block that represents a simple condition
                if (scope.Contains(node))
                {

                    ILBasicBlock block = (ILBasicBlock)node.UserData;
                   
                    {
                        IList<ILExpression> conditions;
                        ILLabel fallLabel;
                        // Switch
                        FakeSwitch fswitch;
                        if (block.MatchLastAndBr(GMCode.Switch, out fswitch, out conditions, out fallLabel))
                        {
                            ILSwitch ilSwitch = new ILSwitch() { Condition = fswitch.SwitchExpression };
                            block.Body[block.Body.Count - 2] = ilSwitch; // replace it, nothing else needs to be done!
                            result.Add(block); // except add it to the result, DOLT
                           
                            scope.RemoveOrThrow(node);// Remove the item so that it is not picked up as content

                            // Pull in code of cases
                            ControlFlowNode fallTarget = null;
                            labelToCfNode.TryGetValue(fallLabel, out fallTarget);

                            HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
                            if (fallTarget != null)
                                frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new[] { fallTarget }));

                            foreach (ILLabel condLabel in fswitch.CaseExpressions.Select(x => x.Value))
                            {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);
                                if (condTarget != null)
                                    frontiers.UnionWith(condTarget.DominanceFrontier.Except(new[] { condTarget }));
                            }
                            for (int i = 0; i < fswitch.CaseExpressions.Count; i++)
                            {
                                ILLabel condLabel = fswitch.CaseExpressions[i].Value;

                                // Find or create new case block
                                ILSwitch.ILCase caseBlock = ilSwitch.Cases.FirstOrDefault(b => b.EntryGoto.Operand == condLabel);
                                if (caseBlock == null)
                                {
                                    caseBlock = new ILSwitch.ILCase()
                                    {
                                        Values = new List<ILExpression>(),
                                        EntryGoto = new ILExpression(GMCode.B, condLabel)
                                    };
                                    ilSwitch.Cases.Add(caseBlock);

                                    ControlFlowNode condTarget = null;
                                    labelToCfNode.TryGetValue(condLabel, out condTarget);
                                    if (condTarget != null && !frontiers.Contains(condTarget))
                                    {
                                        HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
                                        scope.ExceptWith(content);
                                        foreach (var con in FindConditions(content, condTarget)) caseBlock.Body.Add(con);
                                        //   caseBlock.Body.AddRange(FindConditions(content, condTarget));
                                        // Add explicit break which should not be used by default, but the goto removal might decide to use it
                                        caseBlock.Body.Add(new ILBasicBlock()
                                        {
                                            Body = {
                                                ILLabel.Generate("SwitchBreak" ,(int)nextLabelIndex++),
                                                new ILExpression(GMCode.LoopOrSwitchBreak, null)
                                            }
                                        });
                                    }
                                }
                                caseBlock.Values.Add(fswitch.CaseExpressions[i].Key);
                            }

                            // Heuristis to determine if we want to use fallthough as default case
                            if (fallTarget != null && !frontiers.Contains(fallTarget))
                            {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(scope, fallTarget);
                                if (content.Any())
                                {
                                    var caseBlock = new ILSwitch.ILCase() { EntryGoto = new ILExpression(GMCode.B, fallLabel) };
                                    ilSwitch.Cases.Add(caseBlock);
                                    block.Body.RemoveTail(GMCode.B);

                                    scope.ExceptWith(content);
                                    foreach (var con in FindConditions(content, fallTarget)) caseBlock.Body.Add(con);
                                    
                                    // Add explicit break which should not be used by default, but the goto removal might decide to use it
                                    caseBlock.Body.Add(new ILBasicBlock()
                                    { 
                                        Body = {
                                            ILLabel.Generate("SwitchBreak" ,(int)nextLabelIndex++),
                                            new ILExpression(GMCode.LoopOrSwitchBreak, null)
                                        }
                                    });
                                }
                            }
                        }
                     //   Debug.Assert((block.Body.First() as ILLabel).Name != "L1938");
                        // Two-way branch
                        ILLabel trueLabel;
                        ILLabel falseLabel;
                        IList<ILExpression> condExprs;
                        if (block.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExprs, out falseLabel) // be sure to invert this condition
                            && condExprs.Count > 0)  // its resolved
                        {
 
                            ILExpression condExpr = condExprs[0];
                            IList<ILNode> body = block.Body;
                            // this is a simple condition, skip anything short curiket for now
                            // Match a condition patern
                            // Convert the brtrue to ILCondition
                            ILCondition ilCond = new ILCondition()
                            {
                                Condition = condExpr, //code == GMCode.Bf ? condExpr : condExpr.NegateCondition(),
                                TrueBlock = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, trueLabel) },
                                FalseBlock = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, falseLabel) }
                            };
                            block.Body.RemoveTail(GMCode.Bt, GMCode.B);
                            block.Body.Add(ilCond);
                            result.Add(block);

                            // Remove the item immediately so that it is not picked up as content
                            scope.RemoveOrThrow(node);

                            ControlFlowNode trueTarget = null;
                            labelToCfNode.TryGetValue(trueLabel, out trueTarget);
                            ControlFlowNode falseTarget = null;
                            labelToCfNode.TryGetValue(falseLabel, out falseTarget);
   
                            // Pull in the conditional code
                            if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget))
                            {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);
                                scope.ExceptWith(content);
                                foreach (var con in FindConditions(content, trueTarget)) ilCond.TrueBlock.Body.Add(con);
                            }
                            if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget))
                            {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
                                scope.ExceptWith(content);
                                foreach (var con in FindConditions(content, falseTarget)) ilCond.FalseBlock.Body.Add(con);
                            }
                       


                        }
                    }

                    // Add the node now so that we have good ordering
                    if (scope.Contains(node))
                    {
                        result.Add((ILNode)node.UserData);
                        scope.Remove(node);
                    }
                }

                // depth-first traversal of dominator tree
                for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--)
                {
                    agenda.Push(node.DominatorTreeChildren[i]);
                }
            }

            // Add whatever is left
            foreach (var node in scope)
            {
                result.Add((ILNode)node.UserData);
            }

            return result;
        }
		List<ILNode> FindLoops(HashSet<ControlFlowNode> scope, ControlFlowNode entryPoint, bool excludeEntryPoint)
		{
			List<ILNode> result = new List<ILNode>();
			
			// Do not modify entry data
			scope = new HashSet<ControlFlowNode>(scope);
			
			Queue<ControlFlowNode> agenda  = new Queue<ControlFlowNode>();
			agenda.Enqueue(entryPoint);
			while(agenda.Count > 0) {
				ControlFlowNode node = agenda.Dequeue();
				
				// If the node is a loop header
				if (scope.Contains(node)
				    && node.DominanceFrontier.Contains(node)
				    && (node != entryPoint || !excludeEntryPoint))
				{
					HashSet<ControlFlowNode> loopContents = FindLoopContent(scope, node);
					
					// If the first expression is a loop condition
					ILBasicBlock basicBlock = (ILBasicBlock)node.UserData;
					ILExpression condExpr;
					ILLabel trueLabel;
					ILLabel falseLabel;
					// It has to be just brtrue - any preceding code would introduce goto
					if(basicBlock.MatchSingleAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel))
					{
						ControlFlowNode trueTarget;
						labelToCfNode.TryGetValue(trueLabel, out trueTarget);
						ControlFlowNode falseTarget;
						labelToCfNode.TryGetValue(falseLabel, out falseTarget);
						
						// If one point inside the loop and the other outside
						if ((!loopContents.Contains(trueTarget) && loopContents.Contains(falseTarget)) ||
						    (loopContents.Contains(trueTarget) && !loopContents.Contains(falseTarget)) )
						{
							loopContents.RemoveOrThrow(node);
							scope.RemoveOrThrow(node);
							
							// If false means enter the loop
							if (loopContents.Contains(falseTarget) || falseTarget == node)
							{
								// Negate the condition
								condExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
								ILLabel tmp = trueLabel;
								trueLabel = falseLabel;
								falseLabel = tmp;
							}
							
							ControlFlowNode postLoopTarget;
							labelToCfNode.TryGetValue(falseLabel, out postLoopTarget);
							if (postLoopTarget != null) {
								// Pull more nodes into the loop
								HashSet<ControlFlowNode> postLoopContents = FindDominatedNodes(scope, postLoopTarget);
								var pullIn = scope.Except(postLoopContents).Where(n => node.Dominates(n));
								loopContents.UnionWith(pullIn);
							}
							
							// Use loop to implement the brtrue
							basicBlock.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
							basicBlock.Body.Add(new ILWhileLoop() {
								Condition = condExpr,
								BodyBlock = new ILBlock() {
									EntryGoto = new ILExpression(ILCode.Br, trueLabel),
									Body = FindLoops(loopContents, node, false)
								}
							});
							basicBlock.Body.Add(new ILExpression(ILCode.Br, falseLabel));
							result.Add(basicBlock);
							
							scope.ExceptWith(loopContents);
						}
					}
					
					// Fallback method: while(true)
					if (scope.Contains(node)) {
						result.Add(new ILBasicBlock() {
							Body = new List<ILNode>() {
								new ILLabel() { Name = "Loop_" + (nextLabelIndex++) },
								new ILWhileLoop() {
									BodyBlock = new ILBlock() {
										EntryGoto = new ILExpression(ILCode.Br, (ILLabel)basicBlock.Body.First()),
										Body = FindLoops(loopContents, node, true)
									}
								},
							},
						});
						
						scope.ExceptWith(loopContents);
					}
				}

				// Using the dominator tree should ensure we find the the widest loop first
				foreach(var child in node.DominatorTreeChildren) {
					agenda.Enqueue(child);
				}
			}
			
			// Add whatever is left
			foreach(var node in scope) {
				result.Add((ILNode)node.UserData);
			}
			scope.Clear();
			
			return result;
		}
Example #4
0
        List<ILNode> FindLoops(HashSet<ControlFlowNode> scope, ControlFlowNode entryPoint, bool excludeEntryPoint)
        {
            List<ILNode> result = new List<ILNode>();

            // Do not modify entry data
            scope = new HashSet<ControlFlowNode>(scope);

            Queue<ControlFlowNode> agenda = new Queue<ControlFlowNode>();
            agenda.Enqueue(entryPoint);
            while (agenda.Count > 0)
            {
                ControlFlowNode node = agenda.Dequeue();

                // If the node is a loop header
                if (scope.Contains(node)
                    && node.DominanceFrontier.Contains(node)
                    && (node != entryPoint || !excludeEntryPoint))
                {
                    HashSet<ControlFlowNode> loopContents = FindLoopContent(scope, node);

                    // If the first expression is a loop condition
                    ILBasicBlock basicBlock = (ILBasicBlock) node.UserData;
                    ILExpression condExpr = null;
                    ILLabel trueLabel;
                    ILLabel falseLabel;
                    // It has to be just brtrue - any preceding code would introduce goto
                    Debug.Assert(!basicBlock.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel));
                    if (basicBlock.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel) ||
                         basicBlock.MatchLastAndBr(GMCode.Pushenv, out falseLabel, out condExpr, out trueLabel) || // built it the same way from the dissasembler, this needs inverted
                        basicBlock.MatchLastAndBr(GMCode.Repeat, out trueLabel, out condExpr, out falseLabel) ) // repeate loop is built like a while
                       {
                        GMCode loopType = (basicBlock.Body.ElementAt(basicBlock.Body.Count - 2) as ILExpression).Code;
                        ControlFlowNode trueTarget;
                        labelToCfNode.TryGetValue(trueLabel, out trueTarget);
                        ControlFlowNode falseTarget;
                        labelToCfNode.TryGetValue(falseLabel, out falseTarget);

                        // If one point inside the loop and the other outside
                        if ((!loopContents.Contains(trueTarget) && loopContents.Contains(falseTarget)) ||
                            (loopContents.Contains(trueTarget) && !loopContents.Contains(falseTarget)))
                        {
                            loopContents.RemoveOrThrow(node);
                            scope.RemoveOrThrow(node);

                            bool mustNegate = false;
                            if (loopContents.Contains(falseTarget) || falseTarget == node)
                            {
                                // Negate the condition
                                mustNegate = true;
                                //  condExpr = new ILExpression(GMCode.Not, null, condExpr);
                                ILLabel tmp = trueLabel;
                                trueLabel = falseLabel;
                                falseLabel = tmp;
                            }
                            // HACK
                          
                            ControlFlowNode postLoopTarget;
                            labelToCfNode.TryGetValue(falseLabel, out postLoopTarget);
                            if (postLoopTarget != null)
                            {
                                // Pull more nodes into the loop
                                HashSet<ControlFlowNode> postLoopContents = FindDominatedNodes(scope, postLoopTarget);
                                var pullIn = scope.Except(postLoopContents).Where(n => node.Dominates(n));
                                loopContents.UnionWith(pullIn);
                            }


                            //Debug.Assert(false);
                            Debug.Assert(condExpr != null);
                            switch (loopType)
                            {
                                case GMCode.Pushenv:
                                    basicBlock.Body.RemoveTail(GMCode.Pushenv, GMCode.B);
                                    basicBlock.Body.Add(new ILWithStatement()
                                    {
                                        Condition = condExpr, // we never negate 
                                        Body = new ILBlock()
                                        {
                                            EntryGoto = new ILExpression(GMCode.B, trueLabel),
                                            Body = FindLoops(loopContents, node, false)
                                        }
                                    });
                                    break;
                                case GMCode.Bt: 
                                    basicBlock.Body.RemoveTail(GMCode.Bt, GMCode.B);
                                    basicBlock.Body.Add(new ILWhileLoop()
                                    {
                                        Condition = mustNegate ? condExpr.NegateCondition() : condExpr,
                                        Body = new ILBlock()
                                        {
                                            EntryGoto = new ILExpression(GMCode.B, trueLabel),
                                            Body = FindLoops(loopContents, node, false)
                                        }
                                    });
                                   
                                    break;
                                case GMCode.Repeat:
                                    basicBlock.Body.RemoveTail(GMCode.Repeat, GMCode.B);
                                    basicBlock.Body.Add(new ILRepeat()
                                    {
                                        Condition = condExpr, // we never negate 
                                        Body = new ILBlock()
                                        {
                                            EntryGoto = new ILExpression(GMCode.B, trueLabel),
                                            Body = FindLoops(loopContents, node, false)
                                        }
                                    });
                                   
                                    break;
                                    
                            }
                            basicBlock.Body.Add(new ILExpression(GMCode.B, falseLabel));


                            result.Add(basicBlock);

                            scope.ExceptWith(loopContents);
                        }
                    }

                    // Fallback method: while(true)
                    if (scope.Contains(node))
                    {
                        Debug.Assert(false);
                        result.Add(new ILBasicBlock()
                        {
                            Body = new List<ILNode>() {
                                ILLabel.Generate("Loop"),
                                new ILWhileLoop() {
                                    Condition = new ILExpression(GMCode.Constant, new ILValue(true)),
                                    Body = new ILBlock() {
                                        EntryGoto = new ILExpression(GMCode.B, (ILLabel)basicBlock.Body.First()),
                                        Body = FindLoops(loopContents, node, true)
                                    }
                                },
                            },
                        });

                        scope.ExceptWith(loopContents);
                    }
                }

                // Using the dominator tree should ensure we find the the widest loop first
                foreach (var child in node.DominatorTreeChildren)
                {
                    agenda.Enqueue(child);
                }
            }

            // Add whatever is left
            foreach (var node in scope)
            {
                result.Add((ILNode) node.UserData);
            }
            scope.Clear();

            return result;
        }