private void CreateSwitchConstruct(CFGBlockLogicalConstruct switchBlock, ILogicalConstruct parentConstruct, SwitchData switchData, DominatorTree dominatorTree) { List<KeyValuePair<CFGBlockLogicalConstruct, List<int>>> cfgSuccessorToLabelsMap = GetOrderedCFGSuccessorToLabelsMap(switchData); Dictionary<ILogicalConstruct, HashSet<ISingleEntrySubGraph>> validCaseEntryToDominatedNodesMap = GetValidCases(dominatorTree, switchBlock); List<CaseLogicalConstruct> orderedCaseConstructs = new List<CaseLogicalConstruct>(); PairList<List<int>, CFGBlockLogicalConstruct> labelsToCFGSuccessorsList = new PairList<List<int>, CFGBlockLogicalConstruct>(); foreach (KeyValuePair<CFGBlockLogicalConstruct, List<int>> cfgSuccessorToLabelsPair in cfgSuccessorToLabelsMap) { ILogicalConstruct successor; HashSet<ISingleEntrySubGraph> dominatedNodes; if (LogicalFlowUtilities.TryGetParentConstructWithGivenParent(cfgSuccessorToLabelsPair.Key, parentConstruct, out successor) && validCaseEntryToDominatedNodesMap.TryGetValue(successor, out dominatedNodes)) { CaseLogicalConstruct newCaseConstruct = new CaseLogicalConstruct(successor); newCaseConstruct.CaseNumbers.AddRange(cfgSuccessorToLabelsPair.Value); newCaseConstruct.Body.UnionWith(dominatedNodes.Cast<ILogicalConstruct>()); newCaseConstruct.AttachCaseConstructToGraph(); orderedCaseConstructs.Add(newCaseConstruct); } else { labelsToCFGSuccessorsList.Add(cfgSuccessorToLabelsPair.Value, cfgSuccessorToLabelsPair.Key); } } CaseLogicalConstruct defaultCase = null; CFGBlockLogicalConstruct defaultCFGSuccessor = GetCFGLogicalConstructFromBlock(switchData.DefaultCase); ILogicalConstruct defaultSuccessor; HashSet<ISingleEntrySubGraph> defaultCaseNodes; if (LogicalFlowUtilities.TryGetParentConstructWithGivenParent(defaultCFGSuccessor, parentConstruct, out defaultSuccessor) && validCaseEntryToDominatedNodesMap.TryGetValue(defaultSuccessor, out defaultCaseNodes)) { defaultCase = new CaseLogicalConstruct(defaultSuccessor); if (HasSuccessors(defaultCaseNodes)) { defaultCase.Body.UnionWith(defaultCaseNodes.Cast<ILogicalConstruct>()); } defaultCase.AttachCaseConstructToGraph(); } SwitchLogicalConstruct theSwitch = SwitchLogicalConstruct.GroupInSwitchConstruct(switchBlock, orderedCaseConstructs, labelsToCFGSuccessorsList, defaultCase, defaultCFGSuccessor); UpdateDominatorTree(dominatorTree, theSwitch); }
private void UpdateDominatorTree(DominatorTree dominatorTree, LoopLogicalConstruct theLoopConstruct) { HashSet<ISingleEntrySubGraph> loopNodes = new HashSet<ISingleEntrySubGraph>(); if (theLoopConstruct.LoopCondition != null) { loopNodes.Add(theLoopConstruct.LoopCondition); } if (theLoopConstruct.LoopBodyBlock != null) { loopNodes.UnionWith(theLoopConstruct.LoopBodyBlock.Children); } ISingleEntrySubGraph loopEntry = (theLoopConstruct.LoopType == LoopType.PreTestedLoop) ? theLoopConstruct.LoopCondition : theLoopConstruct.LoopBodyBlock.Entry; dominatorTree.MergeNodes(loopNodes, loopEntry, theLoopConstruct); }
/// <summary> /// Determines the type of the loop and the condition of the loop. Adds additional nodes into the loop body. /// </summary> /// <param name="loopBody"></param> /// <param name="header"></param> /// <param name="latchingNodes"></param> /// <param name="interval"></param> /// <param name="loopCondition"></param> /// <returns></returns> private LoopType DetermineLoopType(HashSet<ILogicalConstruct> loopBody, HashSet<ILogicalConstruct> latchingNodes, IntervalConstruct interval, DominatorTree dominatorTree, out ConditionLogicalConstruct loopCondition) { ILogicalConstruct header = interval.Entry as ILogicalConstruct; HashSet<ILogicalConstruct> legalExits = new HashSet<ILogicalConstruct>(latchingNodes); legalExits.Add(header); ILogicalConstruct parentConstruct = header.Parent as ILogicalConstruct; DFSTree dfsTree = DFSTBuilder.BuildTree(parentConstruct); //B - nodes in the loop body (= loopBody) //I - nodes in the interval (= interval.Children) //U - union of all of the dominance frontiers of the nodes in B //exitDominanceFrontier = (U n I) \ B //If a node is in the exitDominanceFrontier, then it is dominated by the header and is a successor (not necessarily direct) of more than one //node in the loop body. HashSet<ILogicalConstruct> exitDominanceFrontier = new HashSet<ILogicalConstruct>(); foreach (ILogicalConstruct loopNode in loopBody) { foreach (ILogicalConstruct frontierNode in dominatorTree.GetDominanceFrontier(loopNode)) { if (interval.Children.Contains(frontierNode) && !loopBody.Contains(frontierNode)) { exitDominanceFrontier.Add(frontierNode); } } } //This is leftover heuristic, that was used for determining a suitable successor that is going to be follow node of the loop. //Changing it now will break a good number of the tests. Since the produced output is acceptable, until a better heuristic is found //there is no need to change it. if (exitDominanceFrontier.Count == 0) { //If the exit dominance frontier is empty then we look for the node, with minimum post order index, that is a successor of a condition loop exit. //The desired exit should be a condition in order to reduce the number of infinite loops (heuristic). foreach (DFSTNode dfsNode in dfsTree.ReversePostOrder) { ILogicalConstruct construct = dfsNode.Construct as ILogicalConstruct; if (loopBody.Contains(construct)) { continue; } loopCondition = GetLoopConditionWithMaxIndex(dfsTree, loopBody, legalExits, construct); //By taking the successor with the minimum post order index and the loop exit with the maximum post order index, we ensure that //the produced construct will always be the same, since the post order in our case is a total order. //There are other various ways of finding the exit-successor pair that can bring consistent output, but none of them is found to yield //better results than the rest. if (loopCondition != null) { //We expand the loop body only when we've found a condition successor of the loop. //This is done in order to avoid adding all of the dominated nodes of an infinite loop to the body. (Better readability of the final code.) //E.g.: An infinite loop on the top level of the logical tree (i.e. child of the method block construct). If it dominates all of its //succeeding nodes then they will be in its interval, which means that they will be added to the loop. As a result there will //be an infinite loop at the end of the method, that encloses a cood part of the code, for no apparent reason. ExpandLoopBody(interval, loopBody, construct); if (loopCondition == header) { return LoopType.PreTestedLoop; } else { return LoopType.PostTestedLoop; } } } if (CanBeLoopCondition(header, loopBody)) { loopCondition = header as ConditionLogicalConstruct; return LoopType.PreTestedLoop; } else { loopCondition = null; return LoopType.InfiniteLoop; } } else { //If there are nodes in the exitDominanceFrontier, then we choose the one with the minimum postorder index for successor of the loop. //Then we try to find a condition exit of the loop, with maximum post order index, that is predecessor of the successor node. int minOrderIndexOfSuccessor = dfsTree.ReversePostOrder.Count; foreach (ILogicalConstruct successor in exitDominanceFrontier) { int currentOrderIndex = dfsTree.ConstructToNodeMap[successor].ReversePostOrderIndex; if(currentOrderIndex < minOrderIndexOfSuccessor) { minOrderIndexOfSuccessor = currentOrderIndex; } } ILogicalConstruct loopSuccessor = dfsTree.ReversePostOrder[minOrderIndexOfSuccessor].Construct as ILogicalConstruct; loopCondition = GetLoopConditionWithMaxIndex(dfsTree, loopBody, legalExits, loopSuccessor); ExpandLoopBody(interval, loopBody, loopSuccessor); if (loopCondition != null) { if (loopCondition == header) { return LoopType.PreTestedLoop; } else { return LoopType.PostTestedLoop; } } else { return LoopType.InfiniteLoop; } } }
/// <summary> /// Analyzes <paramref name="interval"/> and makes a loop from it, if possible. /// </summary> /// <param name="interval">The interval to be analyzed.</param> /// <returns>Returns true if a loop was made.</returns> private bool TryMakeLoop(IntervalConstruct interval, DominatorTree dominatorTree) { DFSTree dfsTree = DFSTBuilder.BuildTree(interval); if (dfsTree.BackEdges.Count == 0) { /// No back edges in the interval, so no loop can be made. return false; } HashSet<ILogicalConstruct> loopBody; HashSet<ILogicalConstruct> possibleLatchingNodes = BuildLoop(dfsTree, out loopBody); ConditionLogicalConstruct loopCondition; LoopType typeOfLoop = DetermineLoopType(loopBody, possibleLatchingNodes, interval, dominatorTree, out loopCondition); if (loopBody.Count > 0) { LoopLogicalConstruct loop = new LoopLogicalConstruct(interval.Entry as ILogicalConstruct, loopBody, typeOfLoop, loopCondition, typeSystem); CleanUpEdges(loop); /// Covers the case in IrregularbackedgeExitLoop UpdateDominatorTree(dominatorTree, loop); return true; } else { /// Empty loops should not be created. Instead, backedges that form such loops will be marked as goto. foreach (DFSTEdge backedge in dfsTree.BackEdges) { MarkAsGotoEdge(backedge.Start.Construct as ILogicalConstruct, backedge.End.Construct as ILogicalConstruct); } } return false; }
/// <summary> /// Tries to build an if construct with condition - the specified condition. /// </summary> /// <remarks> /// The idea is to get the dominated nodes of the true successor to create the then block and the dominated nodes of the false successor /// to create the else block. /// If both the then and else blocks have successors, then they must have a common successor to create the if construct. /// </remarks> /// <param name="condition"></param> /// <returns>True on success.</returns> private bool TryBuildIfConstruct(ConditionLogicalConstruct condition, DominatorTree dominatorTree, DFSTree dfsTree) { //Store the true and false successors for optimization. ILogicalConstruct falseSuccessor = condition.FalseSuccessor; ILogicalConstruct trueSuccessor = condition.TrueSuccessor; HashSet<ISingleEntrySubGraph> falseSuccessorFrontier = dominatorTree.GetDominanceFrontier(falseSuccessor); HashSet<ISingleEntrySubGraph> trueSuccessorFrontier = dominatorTree.GetDominanceFrontier(trueSuccessor); ILogicalConstruct exitSuccessor = CheckSuccessor(condition, trueSuccessor, falseSuccessorFrontier, dfsTree) ?? CheckSuccessor(condition, falseSuccessor, trueSuccessorFrontier, dfsTree); HashSet<ISingleEntrySubGraph> frontierIntersection = new HashSet<ISingleEntrySubGraph>(trueSuccessorFrontier); frontierIntersection.IntersectWith(falseSuccessorFrontier); if (exitSuccessor == null && falseSuccessorFrontier.Count > 0 && trueSuccessorFrontier.Count > 0 && frontierIntersection.Count == 0) { //If none of the successors can be a proper exit and the false and true successor frontiers are not empty but have no common node, //then we do not make the if since it will not have a common exit. return false; } HashSet<ILogicalConstruct> thenBody = GetBlockBody(dominatorTree, trueSuccessor, condition); HashSet<ILogicalConstruct> elseBody = GetBlockBody(dominatorTree, falseSuccessor, condition); if (thenBody == null && elseBody == null) { return false; } else if(thenBody == null) { condition.Negate(typeSystem); ILogicalConstruct swapHelper = trueSuccessor; trueSuccessor = falseSuccessor; falseSuccessor = swapHelper; thenBody = elseBody; elseBody = null; } //If the else body is null but the false successor is not a successor of the then body then we do not make the if. if(elseBody == null && !CheckSuccessors(thenBody, falseSuccessor)) { return false; } if (ShouldInvertIfAndRemoveElse(thenBody, trueSuccessor, elseBody, falseSuccessor)) { ///This is performed for cosmetic reasons. condition.Negate(typeSystem); ILogicalConstruct successorSwapHelper = trueSuccessor; trueSuccessor = falseSuccessor; falseSuccessor = successorSwapHelper; HashSet<ILogicalConstruct> swapHelper = thenBody; thenBody = elseBody; elseBody = swapHelper; elseBody = null; } if (elseBody != null && !HasSuccessors(thenBody) && SubtreeEndsInInstructionCode(trueSuccessor.FirstBlock.TheBlock,new Code[]{Code.Ret, Code.Throw})) // check if all ends are throw and/or return -> allow mixed ends as well { // we don't need the else elseBody = null; } BlockLogicalConstruct theThenBlock = new BlockLogicalConstruct(trueSuccessor, thenBody); BlockLogicalConstruct theElseBlock = elseBody != null ? new BlockLogicalConstruct(falseSuccessor, elseBody) : null; IfLogicalConstruct theIfConstruct = IfLogicalConstruct.GroupInIfConstruct(condition, theThenBlock, theElseBlock); UpdateDominatorTree(dominatorTree, theIfConstruct); return true; }
private void UpdateDominatorTree(DominatorTree dominatorTree, IfLogicalConstruct theIfConstruct) { HashSet<ISingleEntrySubGraph> ifNodes = new HashSet<ISingleEntrySubGraph>(); ifNodes.Add(theIfConstruct.Condition); ifNodes.UnionWith(theIfConstruct.Then.Children); if (theIfConstruct.Else != null) { ifNodes.UnionWith(theIfConstruct.Else.Children); } dominatorTree.MergeNodes(ifNodes, theIfConstruct.Condition, theIfConstruct); }
/// <summary> /// Gets the dominated nodes of the condition successor, only if they can form a legal block for the if construct. /// </summary> /// <param name="dominatorTree"></param> /// <param name="conditionSuccessor"></param> /// <returns>On success - a set of the nodes fo the block. Otherwise it returns null.</returns> private HashSet<ILogicalConstruct> GetBlockBody(DominatorTree dominatorTree, ILogicalConstruct conditionSuccessor, ConditionLogicalConstruct theCondition) { if(conditionSuccessor == dominatorTree.RootConstruct) //Corner case - the successor cannot be the entry of the construct. { return null; } HashSet<ILogicalConstruct> body = null; if(conditionSuccessor.AllPredecessors.Count == 1) //The condition successor must have only one predecessor - the condition. { body = new HashSet<ILogicalConstruct>(); foreach (ILogicalConstruct node in dominatorTree.GetDominatedNodes(conditionSuccessor)) { if (node == theCondition) { return null; } body.Add(node); } } return body; }
private void UpdateDominatorTree(DominatorTree dominatorTree, SwitchLogicalConstruct theSwitchConstruct) { HashSet<ISingleEntrySubGraph> switchNodes = new HashSet<ISingleEntrySubGraph>(); switchNodes.Add(theSwitchConstruct.Entry); foreach (CaseLogicalConstruct @case in theSwitchConstruct.ConditionCases) { switchNodes.UnionWith(@case.Children); } if (theSwitchConstruct.DefaultCase != null) { switchNodes.UnionWith(theSwitchConstruct.DefaultCase.Children); } dominatorTree.MergeNodes(switchNodes, theSwitchConstruct.Entry, theSwitchConstruct); }
private Dictionary<ILogicalConstruct, HashSet<ISingleEntrySubGraph>> GetValidCases(DominatorTree dominatorTree, ILogicalConstruct switchCFGBlock) { Dictionary<ILogicalConstruct, HashSet<ISingleEntrySubGraph>> caseEntriesToDominatedNodesMap = new Dictionary<ILogicalConstruct, HashSet<ISingleEntrySubGraph>>(); HashSet<ISingleEntrySubGraph> legalPredecessors = new HashSet<ISingleEntrySubGraph>(); legalPredecessors.Add(switchCFGBlock); foreach (ILogicalConstruct successor in switchCFGBlock.SameParentSuccessors) { if (successor != switchCFGBlock && dominatorTree.GetImmediateDominator(successor) == switchCFGBlock) { HashSet<ISingleEntrySubGraph> dominatedNodes = dominatorTree.GetDominatedNodes(successor); caseEntriesToDominatedNodesMap.Add(successor, dominatedNodes); legalPredecessors.UnionWith(dominatedNodes); } } DFSTree dfsTree = DFSTBuilder.BuildTree(switchCFGBlock.Parent, switchCFGBlock); List<ILogicalConstruct> orderedCaseEntries = new List<ILogicalConstruct>(dfsTree.ReversePostOrder.Select(node => node.Construct as ILogicalConstruct).Where(construct => caseEntriesToDominatedNodesMap.ContainsKey(construct))); bool changed; do { changed = false; foreach (ILogicalConstruct caseEntry in orderedCaseEntries) { HashSet<ISingleEntrySubGraph> dominatedNodes; if (caseEntriesToDominatedNodesMap.TryGetValue(caseEntry, out dominatedNodes) && !IsCaseValid(caseEntry, legalPredecessors)) { legalPredecessors.ExceptWith(dominatedNodes); caseEntriesToDominatedNodesMap.Remove(caseEntry); changed = true; } } } while (changed); return caseEntriesToDominatedNodesMap; }