public ControlFlowGraph CreateControlFlowGraph(string body) { var code = TestCodeFactory.CreateThreeAddressCode(body); Debug.WriteLine(CodeStringifier.Generate(code)); return(ControlFlowGraphFactory.Create(code)); }
/// <summary> /// Optimizes the given three-address code and returns additional information. /// </summary> /// <param name="code">The code to optimize.</param> /// <returns>A tuple containing the optimized code and a flag identifying if the code received any changes.</returns> public static (Code Code, bool Changed) Optimize(Code code) { var changed = true; var iterations = 0; for (iterations = 0; iterations < MaxOptimizationIterations && changed; ++iterations) { changed = false; foreach (var optimization in _optimizations) { var cfg = ControlFlowGraphFactory.Create(code); var optimized = optimization.Procedure(code, cfg); if (optimized.Changed) { code = optimized.Code; changed = true; Debug.WriteLine($"the three-address code has been optimized by applying the {optimization.Label}"); } } } Debug.WriteLine($"applied {iterations} optimization iterations; change in last iteration: {changed}"); return(code, changed || iterations > 1); }
public void CodeWithSameVariableAndDoubleIntermediateOverwritingDoesNotAffectSucceedingCopies() { var source = @" var x = 0; var y = x; var z = y; x = 5; var a = y; var b = z;"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreNotEqual(code, optimized.Code); Assert.IsTrue(optimized.Changed); var expected = @" DECL x x = 0 DECL y y = x DECL z z = x x = 5 DECL a a = y DECL b b = y"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(optimized.Code)); }
public void CodeWithUsageAndCopyInBranch() { var source = @" var x = 0; var y = 5; if(x > 0) { y = x; var z = y; }"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreNotEqual(code, optimized.Code); Assert.IsTrue(optimized.Changed); var expected = @" DECL x x = 0 DECL y y = 5 IF x > 0 JUMP #0 JUMP #1 LABEL #0 y = x DECL z z = x LABEL #1"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(optimized.Code)); }
public void CopyUsageInCondition() { var source = @" var x = 0; var y = x; if(y == x) { }"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreNotEqual(code, optimized.Code); Assert.IsTrue(optimized.Changed); var expected = @" DECL x x = 0 DECL y y = x IF x == x JUMP #0 JUMP #1 LABEL #0 LABEL #1"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(optimized.Code)); }
public void CopyUsageInArrayAccessor() { var source = @" var x = 0; var y = x; var z = 5 + array[y]"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreNotEqual(code, optimized.Code); Assert.IsTrue(optimized.Changed); var expected = @" DECL x x = 0 DECL y y = x DECL z DECL $temp_0 $temp_0 = array[x] z = 5 + $temp_0"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(optimized.Code)); }
public void CopyUsageInNestedMethodInvocations() { var source = @" var x = 0; var y = x; Outer(x, Inner1(Inner2(y)));"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreNotEqual(code, optimized.Code); Assert.IsTrue(optimized.Changed); var expected = @" DECL x x = 0 DECL y y = x DECL $temp_0 $temp_0 = Inner2(x) DECL $temp_1 $temp_1 = Inner1($temp_0) INVOKE Outer(x, $temp_1)"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(optimized.Code)); }
public void CopyUsageInNestedBinaryExpressions() { var source = @" var x = 0; var y = x; var a = 4; var b = a; var c = x + y * b - y;"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreNotEqual(code, optimized.Code); Assert.IsTrue(optimized.Changed); var expected = @" DECL x x = 0 DECL y y = x DECL a a = 4 DECL b b = a DECL c DECL $temp_0 $temp_0 = x * a DECL $temp_1 $temp_1 = x + $temp_0 c = $temp_1 - x"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(optimized.Code)); }
public void CodeWithCodeWithCopyUsageDoesNotPropagateNestedCopies() { var source = @" var x = 0; var y = x; var z = y; var a = z; var b = a; var c = b;"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreNotEqual(code, optimized.Code); Assert.IsTrue(optimized.Changed); var expected = @" DECL x x = 0 DECL y y = x DECL z z = x DECL a a = y DECL b b = z DECL c c = a"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(optimized.Code)); }
public void BodyWithSingleInvocation() { var invokerSource = @"var a = 10; Method(a);"; var invokerCfg = CreateControlFlowGraph(invokerSource); var methodSource = @" class Test { private void Method(int x) { } }"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(methodSource); var methodCode = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Select(declaration => CodeFactory.CreateMethod(declaration, semanticModel)) .Single(); var methodCfg = ControlFlowGraphFactory.Create(methodCode, "Method", true); var procedureCfgs = new Dictionary <string, ControlFlowGraph> { { "Method", methodCfg } }; var callGraph = CallGraphFactory.Create(invokerCfg, procedureCfgs); Assert.AreEqual(4, callGraph.Edges.Count); Assert.IsTrue(callGraph.Edges.Any(edge => edge.From is FlowInvocation && _IsExpectedTransfer(edge.To, "<root>", "Method", true, false))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedTransfer(edge.From, "<root>", "Method", true, false) && _IsExpectedBoundary(edge.To, "Method", FlowKind.Start))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedBoundary(edge.From, "Method", FlowKind.End) && _IsExpectedTransfer(edge.To, "Method", "<root>", false, true))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedTransfer(edge.From, "Method", "<root>", false, true) && edge.To is FlowInvocation)); Debug.WriteLine(new[] { invokerCfg }.Concat(procedureCfgs.Values).ToDot(callGraph)); }
private ISet <ArrayAccess> _CollectAccesses(string body) { var code = TestCodeFactory.CreateCode(body); var cfg = ControlFlowGraphFactory.Create(code); return(ArrayAccessCollector.Collect(cfg)); }
public void CodeWithoutCopies() { var source = "var x = 0; var y = 2; var z = x + y;"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreEqual(code, optimized.Code); Assert.IsFalse(optimized.Changed); }
public void CodeWithoutCommonSubexpressionsDueToDifferentMethods() { var source = "var x = Method1(1); var y = Method2(1); var z = y * 1;"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CommonSubexpressionElimination.Optimize(code, cfg); Assert.AreEqual(code, optimized.Code); Assert.IsFalse(optimized.Changed); }
public void CommonSubexpressionsWithMultipleInvocationsOfTheSameMethodWithDistinctArguments() { var source = @"var result = Method(x) + Method(y);"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CommonSubexpressionElimination.Optimize(code, cfg); Assert.AreEqual(code, optimized.Code); Assert.IsFalse(optimized.Changed); }
public void EmptyCode() { var source = ""; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreEqual(code, optimized.Code); Assert.IsFalse(optimized.Changed); }
public ControlFlowGraph CreateControlFlowGraph(string methodDeclaration) { var code = $"class Test {{ {methodDeclaration} }}"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(code); var method = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Single(); return(ControlFlowGraphFactory.Create(CodeFactory.CreateMethod(method, semanticModel), true)); }
private ISet <VariableAlias> _CollectAliases(string source) { var semanticModel = _documentFactory.CreateSemanticModel(source); var forStatement = semanticModel.SyntaxTree.GetRoot().DescendantNodes().OfType <ForStatementSyntax>().Single(); var code = CodeFactory.Create(forStatement, semanticModel); var variableAccesses = VariableAccesses.Collect(code); var cfg = ControlFlowGraphFactory.Create(code); return(ExternalArrayAliasCollector.Collect(semanticModel, forStatement, variableAccesses)); }
private bool _HasConflictingArrayAccesses(TLoopStatementSyntax loopStatement, string loopIndex, Code code, VariableAccesses variableAccesses) { var optimized = OptimizationRunner.Optimize(code); code = optimized.Code; variableAccesses = optimized.Changed ? VariableAccesses.Collect(code) : variableAccesses; var cfg = ControlFlowGraphFactory.Create(code, true); var callGraph = CallGraphFactory.Create(cfg, _methods); var calledMethods = callGraph.Methods.Select(methodName => _methods[methodName]).ToImmutableList(); var aliasAnalysis = AliasAnalysis.Analyze(cfg, callGraph, _methods.Values, _GetAliasesAtLoopEntry(loopStatement, variableAccesses)); return(ArrayAccessVerifier.HasConflictingAccesses(loopIndex, cfg, aliasAnalysis, callGraph, calledMethods)); }
public void CodeWithSameVariableButIntermediateOverwriting() { var source = @" var x = 0; var y = x; x = 5; var z = y;"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreEqual(code, optimized.Code); Assert.IsFalse(optimized.Changed); }
public void CodeWithSameInvocationsButIntermediateValueChange() { var source = @" var x = 5; var a = Method(x); x = 2; var b = Method(x);"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CommonSubexpressionElimination.Optimize(code, cfg); Assert.AreEqual(code, optimized.Code); Assert.IsFalse(optimized.Changed); }
public void SelfAssignmentNegatesOptimization() { var source = @" var x = 5; var y = 3; x = x + y; var a = x + y;"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CommonSubexpressionElimination.Optimize(code, cfg); Assert.AreEqual(code, optimized.Code); Assert.IsFalse(optimized.Changed); }
public void CodeWithInLoopCopy() { var source = @" var x = 0; var y = x + 1; for(var i = 0; i < 10; ++i) { x = x + 1; }"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreEqual(code, optimized.Code); Assert.IsFalse(optimized.Changed); }
public void CodeWithBranchOnlyCopy() { var source = @" var x = 0; var y = 2; if(x > 0) { y = x; } var z = y;"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreEqual(code, optimized.Code); Assert.IsFalse(optimized.Changed); }
public void CodeWithSameInvocationsButInLoop() { var source = @" var x = 5; var y = 3; var a = Method(x); for(var i = 0; i < 10; ++i) { x = Method(x); }"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CommonSubexpressionElimination.Optimize(code, cfg); Assert.AreEqual(code, optimized.Code); Assert.IsFalse(optimized.Changed); }
public void CodeWithSameExpressionsButBranchedValueChange() { var source = @" var x = 5; var y = 3; var a = y + x; if(x > y) { x = 2; } var b = y + x;"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CommonSubexpressionElimination.Optimize(code, cfg); Assert.AreEqual(code, optimized.Code); Assert.IsFalse(optimized.Changed); }
public void CommonSubexpressionsInSingleMethodInvocation() { var source = @"Method(x + 1, x + 1);"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CommonSubexpressionElimination.Optimize(code, cfg); Assert.AreNotEqual(code, optimized.Code); Assert.IsTrue(optimized.Changed); var expected = @" DECL $temp_0 $temp_0 = x + 1 DECL $temp_1 $temp_1 = $temp_0 INVOKE Method($temp_0, $temp_1)"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(optimized.Code)); }
public void NestedConditionalExpressions() { var source = @"var x = a > 0 ? 1 : (a < 0 ? 1 : 0);"; var cfg = ControlFlowGraphFactory.Create(TestCodeFactory.CreateThreeAddressCode(source)); var expected = @" digraph cfg { ""0"" [ label = ""<End>"" ]; ""1"" [ label = ""<Start>"" ]; ""2"" [ label = ""Assignment: $temp_0 = $temp_1"" ]; ""3"" [ label = ""Assignment: $temp_0 = 1"" ]; ""4"" [ label = ""Assignment: $temp_1 = 0"" ]; ""5"" [ label = ""Assignment: $temp_1 = 1"" ]; ""6"" [ label = ""Assignment: x = $temp_0"" ]; ""7"" [ label = ""ConditionalJump: a < 0"" ]; ""8"" [ label = ""ConditionalJump: a > 0"" ]; ""9"" [ label = ""Declaration: $temp_0"" ]; ""10"" [ label = ""Declaration: $temp_1"" ]; ""11"" [ label = ""Declaration: x"" ]; ""12"" [ label = ""Label"" ]; ""13"" [ label = ""Label"" ]; ""14"" [ label = ""Label"" ]; ""15"" [ label = ""Label"" ]; ""1"" -> ""11"" [ label = """" ]; ""2"" -> ""15"" [ label = """" ]; ""3"" -> ""15"" [ label = """" ]; ""4"" -> ""14"" [ label = """" ]; ""5"" -> ""14"" [ label = """" ]; ""6"" -> ""0"" [ label = """" ]; ""7"" -> ""4"" [ label = """" ]; ""7"" -> ""13"" [ label = """" ]; ""8"" -> ""10"" [ label = """" ]; ""8"" -> ""12"" [ label = """" ]; ""9"" -> ""8"" [ label = """" ]; ""10"" -> ""7"" [ label = """" ]; ""11"" -> ""9"" [ label = """" ]; ""14"" -> ""2"" [ label = """" ]; ""12"" -> ""3"" [ label = """" ]; ""13"" -> ""5"" [ label = """" ]; ""15"" -> ""6"" [ label = """" ]; }"; Assert.AreEqual(expected.Trim(), cfg.ToDot()); }
public void CodeWithCodeWithSingleCopyUsage() { var source = "var x = 0; var y = x; var z = y;"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CopyPropagation.Optimize(code, cfg); Assert.AreNotEqual(code, optimized.Code); Assert.IsTrue(optimized.Changed); var expected = @" DECL x x = 0 DECL y y = x DECL z z = x"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(optimized.Code)); }
public void CommonSubexpressionsWithMultipleInvocationsOfTheSameMethodWithTheSameArguments() { var source = @"var result = Method(x) + Method(x);"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CommonSubexpressionElimination.Optimize(code, cfg); Assert.AreNotEqual(code, optimized.Code); Assert.IsTrue(optimized.Changed); var expected = @" DECL result DECL $temp_0 $temp_0 = Method(x) DECL $temp_1 $temp_1 = $temp_0 result = $temp_0 + $temp_1"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(optimized.Code)); }
public void CodeWithSingleCommonInvocation() { var source = "var x = 3; var y = Method(x); var z = Method(x);"; var code = TestCodeFactory.CreateThreeAddressCode(source); var cfg = ControlFlowGraphFactory.Create(code); var optimized = CommonSubexpressionElimination.Optimize(code, cfg); Assert.AreNotEqual(code, optimized.Code); Assert.IsTrue(optimized.Changed); var expected = @" DECL x x = 3 DECL y y = Method(x) DECL z z = y"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(optimized.Code)); }