public ControlFlowGraph CreateControlFlowGraph(string body)
        {
            var code = TestCodeFactory.CreateThreeAddressCode(body);

            Debug.WriteLine(CodeStringifier.Generate(code));
            return(ControlFlowGraphFactory.Create(code));
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        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));
        }
예제 #4
0
        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));
        }
예제 #5
0
        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));
        }
예제 #6
0
        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));
        }
예제 #7
0
        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));
        }
예제 #8
0
        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));
        }
예제 #9
0
        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));
        }
예제 #11
0
        private ISet <ArrayAccess> _CollectAccesses(string body)
        {
            var code = TestCodeFactory.CreateCode(body);
            var cfg  = ControlFlowGraphFactory.Create(code);

            return(ArrayAccessCollector.Collect(cfg));
        }
예제 #12
0
        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);
        }
예제 #13
0
        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);
        }
예제 #14
0
        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);
        }
예제 #15
0
        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));
        }
예제 #18
0
            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));
            }
예제 #19
0
        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);
        }
예제 #20
0
        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);
        }
예제 #21
0
        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);
        }
예제 #22
0
        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);
        }
예제 #23
0
        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);
        }
예제 #24
0
        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);
        }
예제 #25
0
        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);
        }
예제 #26
0
        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));
        }
예제 #27
0
        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());
        }
예제 #28
0
        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));
        }
예제 #29
0
        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));
        }
예제 #30
0
        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));
        }