/// <summary> /// Constructs a confrolflow graph /// </summary> /// <param name="globalCode">Ast Tree</param> /// <param name="file">Information about source file</param> private ControlFlowGraph(GlobalCode globalCode, FileInfo file) { File = file; this.globalCode = globalCode; List <Statement> functionsAndClasses = new List <Statement>(); foreach (var statement in globalCode.Statements) { if (statement is TypeDecl || statement is FunctionDecl) { functionsAndClasses.Add(statement); } } foreach (var statement in functionsAndClasses) { globalCode.Statements.Remove(statement); } globalCode.Statements.InsertRange(0, functionsAndClasses); this.visitor = new CFGVisitor(this); globalCode.VisitMe(visitor); PostProcess(visitor); }
/// <summary> /// Function called on end of creating controlflow graph. /// </summary> /// <param name="visitor">visitor which created controlflow graph</param> private void PostProcess(CFGVisitor visitor) { visitor.CheckLabels(); // TODO: simplifying control flow graph currently does not work with worklist segments (see BasicBlock.AfterWorklistSegment) // when CFG is simplifyed, basic blocks corresponding to ends of some segments can be removed => modify SimplifyGraph in order // to not remove empty basic blocks if they end worklist segemnts. //start.SimplifyGraph(); }
/// <summary> /// Constructs a confrolflow graph. This method should be used only for testing with purpose of testing. /// </summary> /// <param name="globalCode">needed for drawing</param> /// <param name="function">function to construct controlflow graph</param> /// <param name="file">Information about source file</param> private ControlFlowGraph(GlobalCode globalCode, MethodDecl function, FileInfo file) { File = file; this.globalCode = globalCode; this.visitor = new CFGVisitor(this); start = visitor.MakeFunctionCFG(function, function.Body); PostProcess(visitor); }
/// <summary> /// Connects TrueBranch and FalseBranch to From. TrueBranch is followed from From if the condition holds, /// FalseBranch is followed from From if the condition does not hold. /// /// If decompose is true, it decomposes the condition expression using logical operations with respect to /// shortcircuit evaluation. /// Note that analyzer now expects that the condition expressions are decomposed and it no longer supports /// condition expressions that are not decomposed. /// </summary> /// <param name="condition">the condition of the branching.</param> /// <param name="From">the basic block where from which the branching starts.</param> /// <param name="TrueBranch">the branch which is taken if the condition holds.</param> /// <param name="FalseBranch">the branch which is taken if the condition does not hold.</param> /// <param name="decompose"></param> internal static void ConnectConditionalBranching(Expression condition, BasicBlock From, BasicBlock TrueBranch, BasicBlock FalseBranch, bool decompose = true) { var binaryCondition = condition as BinaryEx; if (!decompose || binaryCondition == null || (binaryCondition.PublicOperation != Operations.And && binaryCondition.PublicOperation != Operations.Or && binaryCondition.PublicOperation != Operations.Xor)) { ConditionalEdge.AddConditionalEdge(From, TrueBranch, condition); DirectEdge.ConnectDirectEdge(From, FalseBranch); return; } BasicBlock intermediateBasicBlock = null; switch (binaryCondition.PublicOperation) { case Operations.And: intermediateBasicBlock = new BasicBlock(); ConnectConditionalBranching(binaryCondition.LeftExpr, From, intermediateBasicBlock, FalseBranch); From = intermediateBasicBlock; ConnectConditionalBranching(binaryCondition.RightExpr, From, TrueBranch, FalseBranch); break; case Operations.Or: intermediateBasicBlock = new BasicBlock(); ConnectConditionalBranching(binaryCondition.LeftExpr, From, TrueBranch, intermediateBasicBlock); From = intermediateBasicBlock; ConnectConditionalBranching(binaryCondition.RightExpr, From, TrueBranch, FalseBranch); break; case Operations.Xor: // Expands A xor B to (A and !B) || (!A and B) // Expansion expands A to A and !A and B to B and !B // For A and !A we the AST elements cannot be shared (must be unique) - the same for B and !B // We thus make copies of ast elements of left and right expression and use the copies to represent !A and !B var leftNegation = new UnaryEx(Operations.LogicNegation, CFGVisitor.DeepCopyAstExpressionCopyVisitor(binaryCondition.LeftExpr)); var rightNegation = new UnaryEx(Operations.LogicNegation, CFGVisitor.DeepCopyAstExpressionCopyVisitor(binaryCondition.RightExpr)); var leftExpression = new BinaryEx(Operations.And, binaryCondition.LeftExpr, rightNegation); var rightExpression = new BinaryEx(Operations.And, leftNegation, binaryCondition.RightExpr); var xorExpression = new BinaryEx(Operations.Or, leftExpression, rightExpression); ConnectConditionalBranching(xorExpression, From, TrueBranch, FalseBranch); /* * // Translation of xor in the level of control flow graph. More efficient than expansion of AST (translation in the level of program code). * // Does not work because AST of sharing AST elements * var intermediateBasicBlock1 = new BasicBlock(); * var intermediateBasicBlock2 = new BasicBlock(); * VisitIfStmtRec(binaryCondition.LeftExpr, intermediateBasicBlock1, intermediateBasicBlock2); * FromBlock = intermediateBasicBlock1; * VisitIfStmtRec(binaryCondition.RightExpr, FalseSink, TrueSink); * FromBlock = intermediateBasicBlock2; * VisitIfStmtRec(binaryCondition.RightExpr, TrueSink, FalseSink);*/ break; } }